aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/AndroidManifest.xml12
-rw-r--r--java/res/drawable-hdpi/ic_settings_language.pngbin0 -> 986 bytes
-rw-r--r--java/res/drawable-hdpi/ic_setup_wizard.pngbin0 -> 702 bytes
-rw-r--r--java/res/drawable-mdpi/ic_settings_language.pngbin0 -> 756 bytes
-rw-r--r--java/res/drawable-mdpi/ic_setup_wizard.pngbin0 -> 626 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_settings_language.pngbin0 -> 1267 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_setup_wizard.pngbin0 -> 737 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_setup_wizard.pngbin0 -> 892 bytes
-rw-r--r--java/res/layout/input_view.xml6
-rw-r--r--java/res/layout/setup_step.xml58
-rw-r--r--java/res/layout/setup_wizard.xml78
-rw-r--r--java/res/values-af/strings.xml2
-rw-r--r--java/res/values-am/strings.xml2
-rw-r--r--java/res/values-ar/strings.xml2
-rw-r--r--java/res/values-be/strings.xml2
-rw-r--r--java/res/values-bg/strings.xml2
-rw-r--r--java/res/values-ca/strings.xml2
-rw-r--r--java/res/values-cs/strings.xml2
-rw-r--r--java/res/values-da/strings.xml2
-rw-r--r--java/res/values-de/strings.xml2
-rw-r--r--java/res/values-el/strings.xml2
-rw-r--r--java/res/values-en-rGB/strings.xml2
-rw-r--r--java/res/values-es-rUS/strings.xml2
-rw-r--r--java/res/values-es/strings.xml2
-rw-r--r--java/res/values-et/strings.xml2
-rw-r--r--java/res/values-fa/strings.xml2
-rw-r--r--java/res/values-fi/strings.xml2
-rw-r--r--java/res/values-fr/strings.xml2
-rw-r--r--java/res/values-hi/strings.xml2
-rw-r--r--java/res/values-hr/strings.xml2
-rw-r--r--java/res/values-hu/strings.xml2
-rw-r--r--java/res/values-in/strings.xml2
-rw-r--r--java/res/values-is/strings.xml292
-rw-r--r--java/res/values-it/strings.xml2
-rw-r--r--java/res/values-iw/strings.xml2
-rw-r--r--java/res/values-ja/strings.xml2
-rw-r--r--java/res/values-ka/strings.xml292
-rw-r--r--java/res/values-ko/strings.xml2
-rw-r--r--java/res/values-lt/strings.xml2
-rw-r--r--java/res/values-lv/strings.xml2
-rw-r--r--java/res/values-mk/strings.xml292
-rw-r--r--java/res/values-mn/strings.xml292
-rw-r--r--java/res/values-ms/strings.xml2
-rw-r--r--java/res/values-nb/strings.xml2
-rw-r--r--java/res/values-nl/strings.xml2
-rw-r--r--java/res/values-pl/strings.xml2
-rw-r--r--java/res/values-pt-rPT/strings.xml2
-rw-r--r--java/res/values-pt/strings.xml2
-rw-r--r--java/res/values-rm/strings.xml4
-rw-r--r--java/res/values-ro/strings.xml2
-rw-r--r--java/res/values-ru/strings.xml2
-rw-r--r--java/res/values-sk/strings.xml2
-rw-r--r--java/res/values-sl/strings.xml2
-rw-r--r--java/res/values-sr/strings.xml2
-rw-r--r--java/res/values-sv/strings.xml2
-rw-r--r--java/res/values-sw/strings.xml2
-rw-r--r--java/res/values-sw600dp-land/setup-dimens.xml20
-rw-r--r--java/res/values-sw768dp-land/setup-dimens.xml20
-rw-r--r--java/res/values-th/strings.xml2
-rw-r--r--java/res/values-tl/strings.xml2
-rw-r--r--java/res/values-tr/strings.xml2
-rw-r--r--java/res/values-uk/strings.xml2
-rw-r--r--java/res/values-vi/strings.xml2
-rw-r--r--java/res/values-zh-rCN/strings.xml2
-rw-r--r--java/res/values-zh-rTW/strings.xml2
-rw-r--r--java/res/values-zu/strings.xml2
-rw-r--r--java/res/values/colors.xml5
-rw-r--r--java/res/values/setup-dimens.xml20
-rw-r--r--java/res/values/setup-styles.xml45
-rw-r--r--java/res/values/strings.xml51
-rw-r--r--java/res/xml-sw600dp/keys_pcqwerty3_right2.xml24
-rw-r--r--java/res/xml-v16/key_hindi1_shift.xml32
-rw-r--r--java/res/xml-v16/key_hindi3_right.xml36
-rw-r--r--java/res/xml-v16/key_hindi3_shift_left.xml34
-rw-r--r--java/res/xml-v16/key_hindi3_shift_right.xml34
-rw-r--r--java/res/xml-v16/keys_hindi1_left5.xml75
-rw-r--r--java/res/xml-v16/keys_hindi2_left5.xml59
-rw-r--r--java/res/xml-v16/keys_hindi3_left2.xml36
-rw-r--r--java/res/xml/key_hindi1_shift.xml34
-rw-r--r--java/res/xml/key_hindi3_right.xml38
-rw-r--r--java/res/xml/key_hindi3_shift_left.xml36
-rw-r--r--java/res/xml/key_hindi3_shift_right.xml36
-rw-r--r--java/res/xml/key_styles_enter.xml2
-rw-r--r--java/res/xml/keys_hindi1_left5.xml85
-rw-r--r--java/res/xml/keys_hindi2_left5.xml69
-rw-r--r--java/res/xml/keys_hindi3_left2.xml40
-rw-r--r--java/res/xml/keys_pcqwerty3_right2.xml14
-rw-r--r--java/res/xml/prefs.xml13
-rw-r--r--java/res/xml/row_symbols_shift4.xml8
-rw-r--r--java/res/xml/rowkeys_hindi1.xml61
-rw-r--r--java/res/xml/rowkeys_hindi2.xml36
-rw-r--r--java/res/xml/rowkeys_hindi3.xml48
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java17
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java86
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java4
-rw-r--r--java/src/com/android/inputmethod/compat/CompatUtils.java8
-rw-r--r--java/src/com/android/inputmethod/compat/IntentCompatUtils.java36
-rw-r--r--java/src/com/android/inputmethod/compat/TextViewCompatUtils.java44
-rw-r--r--java/src/com/android/inputmethod/compat/ViewCompatUtils.java68
-rw-r--r--java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java8
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java41
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java14
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java980
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java1
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java81
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java10
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java14
-rw-r--r--java/src/com/android/inputmethod/latin/DebugSettings.java2
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java18
-rw-r--r--java/src/com/android/inputmethod/latin/InputTypeUtils.java9
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java82
-rw-r--r--java/src/com/android/inputmethod/latin/LatinImeLogger.java4
-rw-r--r--java/src/com/android/inputmethod/latin/LocaleUtils.java5
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java14
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsFragment.java7
-rw-r--r--java/src/com/android/inputmethod/latin/UserHistoryDictionary.java9
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java3
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java4
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FormatSpec.java14
-rw-r--r--java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java122
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupActivity.java328
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java56
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java4
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java9
-rw-r--r--java/src/com/android/inputmethod/research/LoggingUtils.java38
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java59
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java80
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java167
-rw-r--r--java/src/com/android/inputmethod/research/ResearchSettings.java61
-rw-r--r--java/src/com/android/inputmethod/research/Uploader.java180
-rw-r--r--java/src/com/android/inputmethod/research/UploaderService.java175
134 files changed, 3090 insertions, 2217 deletions
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index b88c18ee5..c05b318b9 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:label="@string/aosp_android_keyboard_ime_name"
android:icon="@mipmap/ic_ime_settings"
@@ -50,12 +51,21 @@
<activity android:name=".setup.SetupActivity"
android:label="@string/aosp_android_keyboard_ime_name"
- android:icon="@mipmap/ic_ime_settings">
+ android:icon="@drawable/ic_setup_wizard">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <receiver android:name=".setup.LauncherIconVisibilityManager">
+ <intent-filter>
+ <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="android.intent.action.USER_INITIALIZE" />
+ </intent-filter>
+ </receiver>
+
<activity android:name="SettingsActivity" android:label="@string/english_ime_settings"
android:uiOptions="splitActionBarWhenNarrow">
<intent-filter>
diff --git a/java/res/drawable-hdpi/ic_settings_language.png b/java/res/drawable-hdpi/ic_settings_language.png
new file mode 100644
index 000000000..f635b2e7a
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_settings_language.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_setup_wizard.png b/java/res/drawable-hdpi/ic_setup_wizard.png
new file mode 100644
index 000000000..38fca6d9d
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_setup_wizard.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_settings_language.png b/java/res/drawable-mdpi/ic_settings_language.png
new file mode 100644
index 000000000..f8aca679b
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_settings_language.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_setup_wizard.png b/java/res/drawable-mdpi/ic_setup_wizard.png
new file mode 100644
index 000000000..66e62b820
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_setup_wizard.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_settings_language.png b/java/res/drawable-xhdpi/ic_settings_language.png
new file mode 100644
index 000000000..2c42db3aa
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_settings_language.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_setup_wizard.png b/java/res/drawable-xhdpi/ic_setup_wizard.png
new file mode 100644
index 000000000..53f70a617
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_setup_wizard.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_setup_wizard.png b/java/res/drawable-xxhdpi/ic_setup_wizard.png
new file mode 100644
index 000000000..6414b4f36
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_setup_wizard.png
Binary files differ
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 40eff3839..136e18cd5 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -43,8 +43,11 @@
android:layout_width="@dimen/suggestions_strip_padding"
android:layout_height="@dimen/suggestions_strip_height"
style="?attr/suggestionsStripBackgroundStyle" />
+ <!-- To ensure that key preview popup is correctly placed when the current system locale is
+ one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
<com.android.inputmethod.latin.suggestions.SuggestionStripView
android:id="@+id/suggestion_strip_view"
+ android:layoutDirection="ltr"
android:layout_weight="1.0"
android:layout_width="0dp"
android:layout_height="@dimen/suggestions_strip_height"
@@ -56,8 +59,11 @@
style="?attr/suggestionsStripBackgroundStyle" />
</LinearLayout>
+ <!-- To ensure that key preview popup is correctly placed when the current system locale is
+ one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
<com.android.inputmethod.keyboard.MainKeyboardView
android:id="@+id/keyboard_view"
+ android:layoutDirection="ltr"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
diff --git a/java/res/layout/setup_step.xml b/java/res/layout/setup_step.xml
new file mode 100644
index 000000000..26d7fe799
--- /dev/null
+++ b/java/res/layout/setup_step.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/setup_step_title"
+ style="@style/setupStepTitleStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp" />
+ <TextView
+ android:id="@+id/setup_step_instruction"
+ style="@style/setupStepInstructionStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp" />
+ <TextView
+ android:id="@+id/setup_step_action_label"
+ style="@style/setupStepActionLabelStyle"
+ android:gravity="center_vertical"
+ android:drawablePadding="12dp"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:clickable="true"
+ android:focusable="true"
+ android:paddingLeft="12dp"
+ android:paddingStart="12dp"
+ android:paddingRight="24dp"
+ android:paddingEnd="24dp" />
+</LinearLayout>
diff --git a/java/res/layout/setup_wizard.xml b/java/res/layout/setup_wizard.xml
new file mode 100644
index 000000000..acbbe30b3
--- /dev/null
+++ b/java/res/layout/setup_wizard.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/setup_background"
+ android:paddingLeft="@dimen/setup_horizontal_padding"
+ android:paddingRight="@dimen/setup_horizontal_padding"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp">
+ <TextView
+ android:id="@+id/setup_title"
+ style="@style/setupTitleStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true" />
+ <LinearLayout
+ android:id="@+id/setup_step_bullets"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/setup_title"
+ android:paddingTop="16dp"
+ android:orientation="horizontal">
+ <TextView
+ style="@style/setupStepBulletStyle"
+ android:text="@string/setup_step1_bullet" />
+ <TextView
+ style="@style/setupStepBulletStyle"
+ android:text="@string/setup_step2_bullet" />
+ <TextView
+ style="@style/setupStepBulletStyle"
+ android:text="@string/setup_step3_bullet" />
+ </LinearLayout>
+ <com.android.inputmethod.latin.setup.SetupStepIndicatorView
+ android:id="@+id/setup_step_indicator"
+ android:layout_width="match_parent"
+ android:layout_height="24dp"
+ android:layout_below="@id/setup_step_bullets" />
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/setup_step_indicator">
+ <include
+ android:id="@+id/setup_step1"
+ layout="@layout/setup_step" />
+ <include
+ android:id="@+id/setup_step2"
+ layout="@layout/setup_step" />
+ <include
+ android:id="@+id/setup_step3"
+ layout="@layout/setup_step" />
+ </FrameLayout>
+ </RelativeLayout>
+</ScrollView>
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index 29d9d7785..4daf46568 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Moet hierdie lêer regtig vir <xliff:g id="LOCALE_NAME">%s</xliff:g> geïnstalleer word?"</string>
<string name="error" msgid="8940763624668513648">"Daar was \'n fout"</string>
<string name="button_default" msgid="3988017840431881491">"Verstek"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Taal en invoer"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Kies invoermetode"</string>
</resources>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index c9bc397de..d1fe341b9 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"እውን ይሄ ፋይል ለ<xliff:g id="LOCALE_NAME">%s</xliff:g> ይጫን?"</string>
<string name="error" msgid="8940763624668513648">"ስህተት ተከስቶ ነበር"</string>
<string name="button_default" msgid="3988017840431881491">"ነባሪ"</string>
+ <string name="language_settings" msgid="1671153053201809031">"ቋንቋ እና ግቤት"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"የግቤት ስልት ይምረጡ"</string>
</resources>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 95fd99f85..bca3c2aa3 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"هل تريد حقًا تثبيت هذا الملف للغة <xliff:g id="LOCALE_NAME">%s</xliff:g>؟"</string>
<string name="error" msgid="8940763624668513648">"حدث خطأ"</string>
<string name="button_default" msgid="3988017840431881491">"الافتراضية"</string>
+ <string name="language_settings" msgid="1671153053201809031">"اللغة والإدخال"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"اختيار أسلوب الإدخال"</string>
</resources>
diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml
index 6de0e0bda..56382e42e 100644
--- a/java/res/values-be/strings.xml
+++ b/java/res/values-be/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Сапраўды ўсталяваць гэты файл на мове: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Была памылка"</string>
<string name="button_default" msgid="3988017840431881491">"Па змаўчанні"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Мова і ўвод"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Выберыце метад уводу"</string>
</resources>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index c971d7b73..3ffebea48 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Наистина ли да се инсталира този файл за <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Възникна грешка"</string>
<string name="button_default" msgid="3988017840431881491">"Стандартни"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Език и въвеждане"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Избор на метод на въвеждане"</string>
</resources>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index 23dcda9d3..26527381f 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Realment vols instal·lar aquest fitxer per a <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"S\'ha produït un error"</string>
<string name="button_default" msgid="3988017840431881491">"Predeterminat"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Idioma i introducció"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Selecció de mètodes d\'introducció"</string>
</resources>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 5625c74fb..7e12f06d8 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Chcete nainstalovat tento soubor pro jazyk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Došlo k chybě"</string>
<string name="button_default" msgid="3988017840431881491">"Výchozí"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Jazyk a zadávání"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Výběr metody zadávání dat"</string>
</resources>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index 6c7936f1d..3ea4aaaef 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Er du klar til at installere denne fil til <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Der opstod en fejl"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Sprog og input"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Vælg inputmetode"</string>
</resources>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index 18fb51bb7..a50cdf0d0 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Möchten Sie diese Datei für <xliff:g id="LOCALE_NAME">%s</xliff:g> installieren?"</string>
<string name="error" msgid="8940763624668513648">"Es ist ein Fehler aufgetreten"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Sprache &amp; Eingabe"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Eingabemethode wählen"</string>
</resources>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index b6d937937..153dbbbf4 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Να εγκατασταθεί όντως αυτό το αρχείο για <xliff:g id="LOCALE_NAME">%s</xliff:g>;"</string>
<string name="error" msgid="8940763624668513648">"Παρουσιάστηκε σφάλμα."</string>
<string name="button_default" msgid="3988017840431881491">"Προεπιλογή"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Γλώσσα και εισαγωγή"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Επιλογή μεθόδου εισαγωγής"</string>
</resources>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index 01ead1bae..5fbbdf667 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Really install this file for <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"There was an error"</string>
<string name="button_default" msgid="3988017840431881491">"Default"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Language &amp; input"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Choose input method"</string>
</resources>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 53d759844..71841f805 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"¿Realmente quieres instalar este archivo para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Se produjo un error."</string>
<string name="button_default" msgid="3988017840431881491">"Predeterminado"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Teclado e idioma"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Seleccionar método de entrada"</string>
</resources>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index 6f54dd6d0..9b31884a2 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"¿Seguro que quieres instalar este archivo para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Se ha producido un error"</string>
<string name="button_default" msgid="3988017840431881491">"Predeterminado"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Idioma y entrada de texto"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Selecciona un método de entrada"</string>
</resources>
diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml
index 9cf6a9ff3..3364abe5e 100644
--- a/java/res/values-et/strings.xml
+++ b/java/res/values-et/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Kas soovite tõesti installida faili lokaadile <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Ilmnes viga"</string>
<string name="button_default" msgid="3988017840431881491">"Vaikeväärtus"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Keeled ja sisestamine"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Valige sisestusmeetod"</string>
</resources>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index 682105894..54ba41256 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -161,4 +161,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"این فایل واقعاً برای <xliff:g id="LOCALE_NAME">%s</xliff:g> نصب شود؟"</string>
<string name="error" msgid="8940763624668513648">"خطایی روی داد"</string>
<string name="button_default" msgid="3988017840431881491">"پیش‌فرض"</string>
+ <string name="language_settings" msgid="1671153053201809031">"زبان و ورودی"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"انتخاب روش ورودی"</string>
</resources>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index 4e55232db..2d754023c 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Haluatko asentaa tämä tiedoston kielelle <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Tapahtui virhe"</string>
<string name="button_default" msgid="3988017840431881491">"Oletusarvot"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Kieli ja syöttötapa"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Valitse syöttötapa"</string>
</resources>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index c552a7f6c..f327f90f9 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Installer ce fichier pour la langue \"<xliff:g id="LOCALE_NAME">%s</xliff:g>\" ?"</string>
<string name="error" msgid="8940763624668513648">"Une erreur s\'est produite"</string>
<string name="button_default" msgid="3988017840431881491">"Par défaut"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Langue et saisie"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Sélectionnez le mode de saisie"</string>
</resources>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 72320ea09..e52143dc6 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"<xliff:g id="LOCALE_NAME">%s</xliff:g> के लिए वास्तव में यह फ़ाइल इंस्टॉल करें?"</string>
<string name="error" msgid="8940763624668513648">"कोई त्रुटि हुई थी"</string>
<string name="button_default" msgid="3988017840431881491">"डिफ़ॉल्ट"</string>
+ <string name="language_settings" msgid="1671153053201809031">"भाषा और इनपुट"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"इनपुट पद्धति चुनें"</string>
</resources>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 8432ed54f..564d48f14 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Želite li doista instalirati ovu datoteku za <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Došlo je do pogreške"</string>
<string name="button_default" msgid="3988017840431881491">"Zadano"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Jezik i unos"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Odabir načina unosa"</string>
</resources>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index eb4bde297..047a31a6c 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Valóban telepíti ezt a fájlt <xliff:g id="LOCALE_NAME">%s</xliff:g> nyelvhez?"</string>
<string name="error" msgid="8940763624668513648">"Hiba történt."</string>
<string name="button_default" msgid="3988017840431881491">"Alapértelmezett"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Nyelv és bevitel"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Beviteli mód kiválasztása"</string>
</resources>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index 646c3aaa2..ba9a7da4c 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Yakin ingin memasang file ini untuk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Terjadi kesalahan"</string>
<string name="button_default" msgid="3988017840431881491">"Default"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Bahasa &amp; masukan"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Pilih metode masukan"</string>
</resources>
diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml
deleted file mode 100644
index 678d3cfc3..000000000
--- a/java/res/values-is/strings.xml
+++ /dev/null
@@ -1,292 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
- <skip />
- <!-- no translation found for english_ime_input_options (3909945612939668554) -->
- <skip />
- <!-- no translation found for english_ime_research_log (8492602295696577851) -->
- <skip />
- <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
- <skip />
- <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
- <skip />
- <!-- no translation found for sound_on_keypress (6093592297198243644) -->
- <skip />
- <!-- no translation found for popup_on_keypress (123894815723512944) -->
- <skip />
- <!-- no translation found for general_category (1859088467017573195) -->
- <skip />
- <!-- no translation found for correction_category (2236750915056607613) -->
- <skip />
- <!-- no translation found for gesture_typing_category (497263612130532630) -->
- <skip />
- <!-- no translation found for misc_category (6894192814868233453) -->
- <skip />
- <!-- no translation found for advanced_settings (362895144495591463) -->
- <skip />
- <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
- <skip />
- <!-- no translation found for show_language_switch_key (5915478828318774384) -->
- <skip />
- <!-- no translation found for show_language_switch_key_summary (7343403647474265713) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview (6604262359510068370) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview_summary (6340524345729093886) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
- <skip />
- <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) -->
- <skip />
- <!-- no translation found for use_contacts_dict (4435317977804180815) -->
- <skip />
- <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
- <skip />
- <!-- no translation found for use_double_space_period (8781529969425082860) -->
- <skip />
- <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
- <skip />
- <!-- no translation found for auto_cap (1719746674854628252) -->
- <skip />
- <!-- no translation found for auto_cap_summary (7934452761022946874) -->
- <skip />
- <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
- <skip />
- <!-- no translation found for main_dictionary (4798763781818361168) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3859783767435239118) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
- <skip />
- <!-- no translation found for auto_correction (7630720885194996950) -->
- <skip />
- <!-- no translation found for auto_correction_summary (5625751551134658006) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
- <skip />
- <!-- no translation found for bigram_prediction (1084449187723948550) -->
- <skip />
- <!-- no translation found for bigram_prediction_summary (3896362682751109677) -->
- <skip />
- <!-- no translation found for gesture_input (826951152254563827) -->
- <skip />
- <!-- no translation found for gesture_input_summary (9180350639305731231) -->
- <skip />
- <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text (4443240334739381053) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) -->
- <skip />
- <!-- no translation found for added_word (8993883354622484372) -->
- <skip />
- <string name="label_go_key" msgid="1635148082137219148">"Áfram"</string>
- <string name="label_next_key" msgid="362972844525672568">"Næsta"</string>
- <string name="label_previous_key" msgid="1211868118071386787">"Fyrra"</string>
- <string name="label_done_key" msgid="2441578748772529288">"Lokið"</string>
- <string name="label_send_key" msgid="2815056534433717444">"Senda"</string>
- <!-- no translation found for label_pause_key (181098308428035340) -->
- <skip />
- <!-- no translation found for label_wait_key (6402152600878093134) -->
- <skip />
- <!-- no translation found for spoken_use_headphones (896961781287283493) -->
- <skip />
- <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
- <skip />
- <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
- <skip />
- <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
- <skip />
- <!-- no translation found for spoken_description_shift (244197883292549308) -->
- <skip />
- <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
- <skip />
- <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
- <skip />
- <!-- no translation found for spoken_description_delete (8740376944276199801) -->
- <skip />
- <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
- <skip />
- <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
- <skip />
- <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
- <skip />
- <!-- no translation found for spoken_description_settings (4627462689603838099) -->
- <skip />
- <!-- no translation found for spoken_description_tab (2667716002663482248) -->
- <skip />
- <!-- no translation found for spoken_description_space (2582521050049860859) -->
- <skip />
- <!-- no translation found for spoken_description_mic (615536748882611950) -->
- <skip />
- <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
- <skip />
- <!-- no translation found for spoken_description_return (8178083177238315647) -->
- <skip />
- <!-- no translation found for spoken_description_search (1247236163755920808) -->
- <skip />
- <!-- no translation found for spoken_description_dot (40711082435231673) -->
- <skip />
- <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
- <skip />
- <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
- <skip />
- <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
- <skip />
- <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
- <skip />
- <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
- <skip />
- <!-- no translation found for voice_input (3583258583521397548) -->
- <skip />
- <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
- <skip />
- <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
- <skip />
- <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
- <skip />
- <!-- no translation found for configure_input_method (373356270290742459) -->
- <skip />
- <!-- no translation found for language_selection_title (1651299598555326750) -->
- <skip />
- <!-- no translation found for select_language (3693815588777926848) -->
- <skip />
- <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
- <skip />
- <!-- no translation found for has_dictionary (6071847973466625007) -->
- <skip />
- <!-- no translation found for prefs_enable_log (6620424505072963557) -->
- <skip />
- <!-- no translation found for prefs_description_log (5827825607258246003) -->
- <skip />
- <!-- no translation found for keyboard_layout (8451164783510487501) -->
- <skip />
- <!-- no translation found for subtype_en_GB (88170601942311355) -->
- <skip />
- <!-- no translation found for subtype_en_US (6160452336634534239) -->
- <skip />
- <!-- no translation found for subtype_es_US (5583145191430180200) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
- <skip />
- <!-- no translation found for subtype_with_layout_es_US (6261791057007890189) -->
- <skip />
- <!-- no translation found for subtype_no_language (141420857808801746) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
- <skip />
- <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
- <skip />
- <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
- <skip />
- <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
- <skip />
- <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
- <skip />
- <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
- <skip />
- <!-- no translation found for add_style (6163126614514489951) -->
- <skip />
- <!-- no translation found for add (8299699805688017798) -->
- <skip />
- <!-- no translation found for remove (4486081658752944606) -->
- <skip />
- <!-- no translation found for save (7646738597196767214) -->
- <skip />
- <!-- no translation found for subtype_locale (8576443440738143764) -->
- <skip />
- <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
- <skip />
- <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
- <skip />
- <!-- no translation found for enable (5031294444630523247) -->
- <skip />
- <!-- no translation found for not_now (6172462888202790482) -->
- <skip />
- <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
- <skip />
- <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
- <skip />
- <!-- no translation found for prefs_key_longpress_timeout_settings (1881822418815012326) -->
- <skip />
- <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
- <skip />
- <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
- <skip />
- <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) -->
- <skip />
- <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) -->
- <skip />
- <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) -->
- <skip />
- <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) -->
- <skip />
- <!-- no translation found for error (8940763624668513648) -->
- <skip />
- <!-- no translation found for button_default (3988017840431881491) -->
- <skip />
-</resources>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index e353d8e9b..56acdf8ce 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Installare questo file per <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Si è verificato un errore"</string>
<string name="button_default" msgid="3988017840431881491">"Predefinito"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Lingua e input"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Scegli il metodo di immissione"</string>
</resources>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index e537efba9..7c55ab569 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"האם באמת להתקין את הקובץ הזה עבור <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"אירעה שגיאה"</string>
<string name="button_default" msgid="3988017840431881491">"ברירת מחדל"</string>
+ <string name="language_settings" msgid="1671153053201809031">"שפה וקלט"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"בחירת שיטת קלט"</string>
</resources>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index 9aedb6d9a..9328f0184 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"この<xliff:g id="LOCALE_NAME">%s</xliff:g>のファイルをインストールしてもよろしいですか?"</string>
<string name="error" msgid="8940763624668513648">"エラーが発生しました"</string>
<string name="button_default" msgid="3988017840431881491">"デフォルト"</string>
+ <string name="language_settings" msgid="1671153053201809031">"言語と入力"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"入力方法の選択"</string>
</resources>
diff --git a/java/res/values-ka/strings.xml b/java/res/values-ka/strings.xml
deleted file mode 100644
index 4c0f17c86..000000000
--- a/java/res/values-ka/strings.xml
+++ /dev/null
@@ -1,292 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
- <skip />
- <!-- no translation found for english_ime_input_options (3909945612939668554) -->
- <skip />
- <!-- no translation found for english_ime_research_log (8492602295696577851) -->
- <skip />
- <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
- <skip />
- <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
- <skip />
- <!-- no translation found for sound_on_keypress (6093592297198243644) -->
- <skip />
- <!-- no translation found for popup_on_keypress (123894815723512944) -->
- <skip />
- <!-- no translation found for general_category (1859088467017573195) -->
- <skip />
- <!-- no translation found for correction_category (2236750915056607613) -->
- <skip />
- <!-- no translation found for gesture_typing_category (497263612130532630) -->
- <skip />
- <!-- no translation found for misc_category (6894192814868233453) -->
- <skip />
- <!-- no translation found for advanced_settings (362895144495591463) -->
- <skip />
- <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
- <skip />
- <!-- no translation found for show_language_switch_key (5915478828318774384) -->
- <skip />
- <!-- no translation found for show_language_switch_key_summary (7343403647474265713) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview (6604262359510068370) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview_summary (6340524345729093886) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
- <skip />
- <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) -->
- <skip />
- <!-- no translation found for use_contacts_dict (4435317977804180815) -->
- <skip />
- <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
- <skip />
- <!-- no translation found for use_double_space_period (8781529969425082860) -->
- <skip />
- <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
- <skip />
- <!-- no translation found for auto_cap (1719746674854628252) -->
- <skip />
- <!-- no translation found for auto_cap_summary (7934452761022946874) -->
- <skip />
- <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
- <skip />
- <!-- no translation found for main_dictionary (4798763781818361168) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3859783767435239118) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
- <skip />
- <!-- no translation found for auto_correction (7630720885194996950) -->
- <skip />
- <!-- no translation found for auto_correction_summary (5625751551134658006) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
- <skip />
- <!-- no translation found for bigram_prediction (1084449187723948550) -->
- <skip />
- <!-- no translation found for bigram_prediction_summary (3896362682751109677) -->
- <skip />
- <!-- no translation found for gesture_input (826951152254563827) -->
- <skip />
- <!-- no translation found for gesture_input_summary (9180350639305731231) -->
- <skip />
- <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text (4443240334739381053) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) -->
- <skip />
- <!-- no translation found for added_word (8993883354622484372) -->
- <skip />
- <string name="label_go_key" msgid="1635148082137219148">"გადასვლა"</string>
- <string name="label_next_key" msgid="362972844525672568">"შემდეგი"</string>
- <string name="label_previous_key" msgid="1211868118071386787">"წინა"</string>
- <string name="label_done_key" msgid="2441578748772529288">"შესრულებულია"</string>
- <string name="label_send_key" msgid="2815056534433717444">"გაგზავნა"</string>
- <!-- no translation found for label_pause_key (181098308428035340) -->
- <skip />
- <!-- no translation found for label_wait_key (6402152600878093134) -->
- <skip />
- <!-- no translation found for spoken_use_headphones (896961781287283493) -->
- <skip />
- <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
- <skip />
- <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
- <skip />
- <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
- <skip />
- <!-- no translation found for spoken_description_shift (244197883292549308) -->
- <skip />
- <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
- <skip />
- <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
- <skip />
- <!-- no translation found for spoken_description_delete (8740376944276199801) -->
- <skip />
- <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
- <skip />
- <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
- <skip />
- <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
- <skip />
- <!-- no translation found for spoken_description_settings (4627462689603838099) -->
- <skip />
- <!-- no translation found for spoken_description_tab (2667716002663482248) -->
- <skip />
- <!-- no translation found for spoken_description_space (2582521050049860859) -->
- <skip />
- <!-- no translation found for spoken_description_mic (615536748882611950) -->
- <skip />
- <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
- <skip />
- <!-- no translation found for spoken_description_return (8178083177238315647) -->
- <skip />
- <!-- no translation found for spoken_description_search (1247236163755920808) -->
- <skip />
- <!-- no translation found for spoken_description_dot (40711082435231673) -->
- <skip />
- <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
- <skip />
- <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
- <skip />
- <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
- <skip />
- <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
- <skip />
- <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
- <skip />
- <!-- no translation found for voice_input (3583258583521397548) -->
- <skip />
- <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
- <skip />
- <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
- <skip />
- <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
- <skip />
- <!-- no translation found for configure_input_method (373356270290742459) -->
- <skip />
- <!-- no translation found for language_selection_title (1651299598555326750) -->
- <skip />
- <!-- no translation found for select_language (3693815588777926848) -->
- <skip />
- <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
- <skip />
- <!-- no translation found for has_dictionary (6071847973466625007) -->
- <skip />
- <!-- no translation found for prefs_enable_log (6620424505072963557) -->
- <skip />
- <!-- no translation found for prefs_description_log (5827825607258246003) -->
- <skip />
- <!-- no translation found for keyboard_layout (8451164783510487501) -->
- <skip />
- <!-- no translation found for subtype_en_GB (88170601942311355) -->
- <skip />
- <!-- no translation found for subtype_en_US (6160452336634534239) -->
- <skip />
- <!-- no translation found for subtype_es_US (5583145191430180200) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
- <skip />
- <!-- no translation found for subtype_with_layout_es_US (6261791057007890189) -->
- <skip />
- <!-- no translation found for subtype_no_language (141420857808801746) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
- <skip />
- <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
- <skip />
- <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
- <skip />
- <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
- <skip />
- <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
- <skip />
- <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
- <skip />
- <!-- no translation found for add_style (6163126614514489951) -->
- <skip />
- <!-- no translation found for add (8299699805688017798) -->
- <skip />
- <!-- no translation found for remove (4486081658752944606) -->
- <skip />
- <!-- no translation found for save (7646738597196767214) -->
- <skip />
- <!-- no translation found for subtype_locale (8576443440738143764) -->
- <skip />
- <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
- <skip />
- <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
- <skip />
- <!-- no translation found for enable (5031294444630523247) -->
- <skip />
- <!-- no translation found for not_now (6172462888202790482) -->
- <skip />
- <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
- <skip />
- <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
- <skip />
- <!-- no translation found for prefs_key_longpress_timeout_settings (1881822418815012326) -->
- <skip />
- <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
- <skip />
- <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
- <skip />
- <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) -->
- <skip />
- <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) -->
- <skip />
- <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) -->
- <skip />
- <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) -->
- <skip />
- <!-- no translation found for error (8940763624668513648) -->
- <skip />
- <!-- no translation found for button_default (3988017840431881491) -->
- <skip />
-</resources>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 13fb4cf24..f6086eed5 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"이 파일을 <xliff:g id="LOCALE_NAME">%s</xliff:g>(으)로 설치하시겠습니까?"</string>
<string name="error" msgid="8940763624668513648">"오류 발생"</string>
<string name="button_default" msgid="3988017840431881491">"기본값"</string>
+ <string name="language_settings" msgid="1671153053201809031">"언어 및 키보드"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"입력 방법 선택"</string>
</resources>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index b023a17f5..a815003b2 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Ar tikrai įdiegti šį failą <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Įvyko klaida"</string>
<string name="button_default" msgid="3988017840431881491">"Numatytieji"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Kalba ir įvestis"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Pasirinkite įvesties metodą"</string>
</resources>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 23be520a4..6a408cfce 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Vai instalēt šo failu šādai valodai: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Radās kļūda"</string>
<string name="button_default" msgid="3988017840431881491">"Noklusējums"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Valoda un ievade"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Ievades metodes izvēle"</string>
</resources>
diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml
deleted file mode 100644
index e7189d5c2..000000000
--- a/java/res/values-mk/strings.xml
+++ /dev/null
@@ -1,292 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
- <skip />
- <!-- no translation found for english_ime_input_options (3909945612939668554) -->
- <skip />
- <!-- no translation found for english_ime_research_log (8492602295696577851) -->
- <skip />
- <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
- <skip />
- <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
- <skip />
- <!-- no translation found for sound_on_keypress (6093592297198243644) -->
- <skip />
- <!-- no translation found for popup_on_keypress (123894815723512944) -->
- <skip />
- <!-- no translation found for general_category (1859088467017573195) -->
- <skip />
- <!-- no translation found for correction_category (2236750915056607613) -->
- <skip />
- <!-- no translation found for gesture_typing_category (497263612130532630) -->
- <skip />
- <!-- no translation found for misc_category (6894192814868233453) -->
- <skip />
- <!-- no translation found for advanced_settings (362895144495591463) -->
- <skip />
- <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
- <skip />
- <!-- no translation found for show_language_switch_key (5915478828318774384) -->
- <skip />
- <!-- no translation found for show_language_switch_key_summary (7343403647474265713) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview (6604262359510068370) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview_summary (6340524345729093886) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
- <skip />
- <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) -->
- <skip />
- <!-- no translation found for use_contacts_dict (4435317977804180815) -->
- <skip />
- <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
- <skip />
- <!-- no translation found for use_double_space_period (8781529969425082860) -->
- <skip />
- <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
- <skip />
- <!-- no translation found for auto_cap (1719746674854628252) -->
- <skip />
- <!-- no translation found for auto_cap_summary (7934452761022946874) -->
- <skip />
- <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
- <skip />
- <!-- no translation found for main_dictionary (4798763781818361168) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3859783767435239118) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
- <skip />
- <!-- no translation found for auto_correction (7630720885194996950) -->
- <skip />
- <!-- no translation found for auto_correction_summary (5625751551134658006) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
- <skip />
- <!-- no translation found for bigram_prediction (1084449187723948550) -->
- <skip />
- <!-- no translation found for bigram_prediction_summary (3896362682751109677) -->
- <skip />
- <!-- no translation found for gesture_input (826951152254563827) -->
- <skip />
- <!-- no translation found for gesture_input_summary (9180350639305731231) -->
- <skip />
- <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text (4443240334739381053) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) -->
- <skip />
- <!-- no translation found for added_word (8993883354622484372) -->
- <skip />
- <string name="label_go_key" msgid="1635148082137219148">"Оди"</string>
- <string name="label_next_key" msgid="362972844525672568">"Следно"</string>
- <string name="label_previous_key" msgid="1211868118071386787">"Претходно"</string>
- <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
- <string name="label_send_key" msgid="2815056534433717444">"Испрати"</string>
- <!-- no translation found for label_pause_key (181098308428035340) -->
- <skip />
- <!-- no translation found for label_wait_key (6402152600878093134) -->
- <skip />
- <!-- no translation found for spoken_use_headphones (896961781287283493) -->
- <skip />
- <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
- <skip />
- <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
- <skip />
- <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
- <skip />
- <!-- no translation found for spoken_description_shift (244197883292549308) -->
- <skip />
- <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
- <skip />
- <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
- <skip />
- <!-- no translation found for spoken_description_delete (8740376944276199801) -->
- <skip />
- <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
- <skip />
- <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
- <skip />
- <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
- <skip />
- <!-- no translation found for spoken_description_settings (4627462689603838099) -->
- <skip />
- <!-- no translation found for spoken_description_tab (2667716002663482248) -->
- <skip />
- <!-- no translation found for spoken_description_space (2582521050049860859) -->
- <skip />
- <!-- no translation found for spoken_description_mic (615536748882611950) -->
- <skip />
- <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
- <skip />
- <!-- no translation found for spoken_description_return (8178083177238315647) -->
- <skip />
- <!-- no translation found for spoken_description_search (1247236163755920808) -->
- <skip />
- <!-- no translation found for spoken_description_dot (40711082435231673) -->
- <skip />
- <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
- <skip />
- <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
- <skip />
- <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
- <skip />
- <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
- <skip />
- <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
- <skip />
- <!-- no translation found for voice_input (3583258583521397548) -->
- <skip />
- <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
- <skip />
- <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
- <skip />
- <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
- <skip />
- <!-- no translation found for configure_input_method (373356270290742459) -->
- <skip />
- <!-- no translation found for language_selection_title (1651299598555326750) -->
- <skip />
- <!-- no translation found for select_language (3693815588777926848) -->
- <skip />
- <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
- <skip />
- <!-- no translation found for has_dictionary (6071847973466625007) -->
- <skip />
- <!-- no translation found for prefs_enable_log (6620424505072963557) -->
- <skip />
- <!-- no translation found for prefs_description_log (5827825607258246003) -->
- <skip />
- <!-- no translation found for keyboard_layout (8451164783510487501) -->
- <skip />
- <!-- no translation found for subtype_en_GB (88170601942311355) -->
- <skip />
- <!-- no translation found for subtype_en_US (6160452336634534239) -->
- <skip />
- <!-- no translation found for subtype_es_US (5583145191430180200) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
- <skip />
- <!-- no translation found for subtype_with_layout_es_US (6261791057007890189) -->
- <skip />
- <!-- no translation found for subtype_no_language (141420857808801746) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
- <skip />
- <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
- <skip />
- <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
- <skip />
- <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
- <skip />
- <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
- <skip />
- <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
- <skip />
- <!-- no translation found for add_style (6163126614514489951) -->
- <skip />
- <!-- no translation found for add (8299699805688017798) -->
- <skip />
- <!-- no translation found for remove (4486081658752944606) -->
- <skip />
- <!-- no translation found for save (7646738597196767214) -->
- <skip />
- <!-- no translation found for subtype_locale (8576443440738143764) -->
- <skip />
- <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
- <skip />
- <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
- <skip />
- <!-- no translation found for enable (5031294444630523247) -->
- <skip />
- <!-- no translation found for not_now (6172462888202790482) -->
- <skip />
- <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
- <skip />
- <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
- <skip />
- <!-- no translation found for prefs_key_longpress_timeout_settings (1881822418815012326) -->
- <skip />
- <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
- <skip />
- <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
- <skip />
- <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) -->
- <skip />
- <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) -->
- <skip />
- <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) -->
- <skip />
- <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) -->
- <skip />
- <!-- no translation found for error (8940763624668513648) -->
- <skip />
- <!-- no translation found for button_default (3988017840431881491) -->
- <skip />
-</resources>
diff --git a/java/res/values-mn/strings.xml b/java/res/values-mn/strings.xml
deleted file mode 100644
index 0372701db..000000000
--- a/java/res/values-mn/strings.xml
+++ /dev/null
@@ -1,292 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
- <skip />
- <!-- no translation found for english_ime_input_options (3909945612939668554) -->
- <skip />
- <!-- no translation found for english_ime_research_log (8492602295696577851) -->
- <skip />
- <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
- <skip />
- <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
- <skip />
- <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
- <skip />
- <!-- no translation found for sound_on_keypress (6093592297198243644) -->
- <skip />
- <!-- no translation found for popup_on_keypress (123894815723512944) -->
- <skip />
- <!-- no translation found for general_category (1859088467017573195) -->
- <skip />
- <!-- no translation found for correction_category (2236750915056607613) -->
- <skip />
- <!-- no translation found for gesture_typing_category (497263612130532630) -->
- <skip />
- <!-- no translation found for misc_category (6894192814868233453) -->
- <skip />
- <!-- no translation found for advanced_settings (362895144495591463) -->
- <skip />
- <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
- <skip />
- <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
- <skip />
- <!-- no translation found for show_language_switch_key (5915478828318774384) -->
- <skip />
- <!-- no translation found for show_language_switch_key_summary (7343403647474265713) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview (6604262359510068370) -->
- <skip />
- <!-- no translation found for sliding_key_input_preview_summary (6340524345729093886) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
- <skip />
- <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
- <skip />
- <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) -->
- <skip />
- <!-- no translation found for use_contacts_dict (4435317977804180815) -->
- <skip />
- <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
- <skip />
- <!-- no translation found for use_double_space_period (8781529969425082860) -->
- <skip />
- <!-- no translation found for use_double_space_period_summary (6532892187247952799) -->
- <skip />
- <!-- no translation found for auto_cap (1719746674854628252) -->
- <skip />
- <!-- no translation found for auto_cap_summary (7934452761022946874) -->
- <skip />
- <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
- <skip />
- <!-- no translation found for main_dictionary (4798763781818361168) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
- <skip />
- <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3859783767435239118) -->
- <skip />
- <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
- <skip />
- <!-- no translation found for auto_correction (7630720885194996950) -->
- <skip />
- <!-- no translation found for auto_correction_summary (5625751551134658006) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
- <skip />
- <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
- <skip />
- <!-- no translation found for bigram_prediction (1084449187723948550) -->
- <skip />
- <!-- no translation found for bigram_prediction_summary (3896362682751109677) -->
- <skip />
- <!-- no translation found for gesture_input (826951152254563827) -->
- <skip />
- <!-- no translation found for gesture_input_summary (9180350639305731231) -->
- <skip />
- <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text (4443240334739381053) -->
- <skip />
- <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) -->
- <skip />
- <!-- no translation found for added_word (8993883354622484372) -->
- <skip />
- <string name="label_go_key" msgid="1635148082137219148">"Очих"</string>
- <string name="label_next_key" msgid="362972844525672568">"Дараагийн"</string>
- <string name="label_previous_key" msgid="1211868118071386787">"Өмнөх"</string>
- <string name="label_done_key" msgid="2441578748772529288">"Хийгдлээ"</string>
- <string name="label_send_key" msgid="2815056534433717444">"Илгээх"</string>
- <!-- no translation found for label_pause_key (181098308428035340) -->
- <skip />
- <!-- no translation found for label_wait_key (6402152600878093134) -->
- <skip />
- <!-- no translation found for spoken_use_headphones (896961781287283493) -->
- <skip />
- <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
- <skip />
- <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
- <skip />
- <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
- <skip />
- <!-- no translation found for spoken_description_shift (244197883292549308) -->
- <skip />
- <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
- <skip />
- <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
- <skip />
- <!-- no translation found for spoken_description_delete (8740376944276199801) -->
- <skip />
- <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
- <skip />
- <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
- <skip />
- <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
- <skip />
- <!-- no translation found for spoken_description_settings (4627462689603838099) -->
- <skip />
- <!-- no translation found for spoken_description_tab (2667716002663482248) -->
- <skip />
- <!-- no translation found for spoken_description_space (2582521050049860859) -->
- <skip />
- <!-- no translation found for spoken_description_mic (615536748882611950) -->
- <skip />
- <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
- <skip />
- <!-- no translation found for spoken_description_return (8178083177238315647) -->
- <skip />
- <!-- no translation found for spoken_description_search (1247236163755920808) -->
- <skip />
- <!-- no translation found for spoken_description_dot (40711082435231673) -->
- <skip />
- <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
- <skip />
- <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
- <skip />
- <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
- <skip />
- <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
- <skip />
- <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
- <skip />
- <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
- <skip />
- <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
- <skip />
- <!-- no translation found for voice_input (3583258583521397548) -->
- <skip />
- <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
- <skip />
- <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
- <skip />
- <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
- <skip />
- <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
- <skip />
- <!-- no translation found for configure_input_method (373356270290742459) -->
- <skip />
- <!-- no translation found for language_selection_title (1651299598555326750) -->
- <skip />
- <!-- no translation found for select_language (3693815588777926848) -->
- <skip />
- <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
- <skip />
- <!-- no translation found for has_dictionary (6071847973466625007) -->
- <skip />
- <!-- no translation found for prefs_enable_log (6620424505072963557) -->
- <skip />
- <!-- no translation found for prefs_description_log (5827825607258246003) -->
- <skip />
- <!-- no translation found for keyboard_layout (8451164783510487501) -->
- <skip />
- <!-- no translation found for subtype_en_GB (88170601942311355) -->
- <skip />
- <!-- no translation found for subtype_en_US (6160452336634534239) -->
- <skip />
- <!-- no translation found for subtype_es_US (5583145191430180200) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
- <skip />
- <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
- <skip />
- <!-- no translation found for subtype_with_layout_es_US (6261791057007890189) -->
- <skip />
- <!-- no translation found for subtype_no_language (141420857808801746) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
- <skip />
- <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
- <skip />
- <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
- <skip />
- <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
- <skip />
- <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
- <skip />
- <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
- <skip />
- <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
- <skip />
- <!-- no translation found for add_style (6163126614514489951) -->
- <skip />
- <!-- no translation found for add (8299699805688017798) -->
- <skip />
- <!-- no translation found for remove (4486081658752944606) -->
- <skip />
- <!-- no translation found for save (7646738597196767214) -->
- <skip />
- <!-- no translation found for subtype_locale (8576443440738143764) -->
- <skip />
- <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
- <skip />
- <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
- <skip />
- <!-- no translation found for enable (5031294444630523247) -->
- <skip />
- <!-- no translation found for not_now (6172462888202790482) -->
- <skip />
- <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
- <skip />
- <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
- <skip />
- <!-- no translation found for prefs_key_longpress_timeout_settings (1881822418815012326) -->
- <skip />
- <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
- <skip />
- <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
- <skip />
- <!-- no translation found for prefs_read_external_dictionary (2588931418575013067) -->
- <skip />
- <!-- no translation found for read_external_dictionary_no_files_message (4947420942224623792) -->
- <skip />
- <!-- no translation found for read_external_dictionary_multiple_files_title (7637749044265808628) -->
- <skip />
- <!-- no translation found for read_external_dictionary_confirm_install_message (6898610163768980870) -->
- <skip />
- <!-- no translation found for error (8940763624668513648) -->
- <skip />
- <!-- no translation found for button_default (3988017840431881491) -->
- <skip />
-</resources>
diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml
index 37f923c26..0d4ccf42d 100644
--- a/java/res/values-ms/strings.xml
+++ b/java/res/values-ms/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Betul-betul pasang fail ini untuk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Berlaku ralat"</string>
<string name="button_default" msgid="3988017840431881491">"Lalai"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Bahasa &amp; input"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Pilih kaedah input"</string>
</resources>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index b79933f46..f0b3a4623 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Vil du virkelig installere denne filen for <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Det oppsto en feil"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Språk og inndata"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Velg inndatametode"</string>
</resources>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index 3dba9833b..dc3a9c3f4 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Wilt u dit bestand voor <xliff:g id="LOCALE_NAME">%s</xliff:g> echt installeren?"</string>
<string name="error" msgid="8940763624668513648">"Er is een fout opgetreden"</string>
<string name="button_default" msgid="3988017840431881491">"Standaard"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Taal en invoer"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Invoermethode selecteren"</string>
</resources>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index 11602b8fa..de100bc86 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Czy na pewno zainstalować ten plik dla języka: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Wystąpił błąd"</string>
<string name="button_default" msgid="3988017840431881491">"Domyślne"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Język, klawiatura, głos"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Wybierz metodę wprowadzania"</string>
</resources>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index 6e650154f..68a34574f 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Instalar mesmo este ficheiro para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Ocorreu um erro"</string>
<string name="button_default" msgid="3988017840431881491">"Predefinido"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Idioma e entrada de som"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Escolher o método de entrada"</string>
</resources>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 33f5ecaa5..00ab88ced 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Deseja instalar este arquivo para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Ocorreu um erro"</string>
<string name="button_default" msgid="3988017840431881491">"Padrão"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Idioma e entrada"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Selecione o método de entrada"</string>
</resources>
diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml
index bbef69da4..9eec7f883 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -281,4 +281,8 @@
<skip />
<!-- no translation found for button_default (3988017840431881491) -->
<skip />
+ <!-- no translation found for language_settings (1671153053201809031) -->
+ <skip />
+ <!-- no translation found for select_input_method (4301602374609275003) -->
+ <skip />
</resources>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 5c6ff3fcc..c5a80e397 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Doriți să instalați acest fișier pentru <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"A apărut o eroare"</string>
<string name="button_default" msgid="3988017840431881491">"Prestabilit"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Limbă și introducere de text"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Alegeți metoda de introducere de text"</string>
</resources>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 5e746bb06..13a567808 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Установить этот файл для следующего языка: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Ошибка"</string>
<string name="button_default" msgid="3988017840431881491">"По умолчанию"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Язык и ввод"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Выберите способ ввода"</string>
</resources>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index 9fd979865..0b28bf193 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Chcete nainštalovať tento súbor pre jazyk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Vyskytla sa chyba"</string>
<string name="button_default" msgid="3988017840431881491">"Predvolené"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Jazyk &amp; vstup"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Zvoliť metódu vstupu"</string>
</resources>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index fa441d712..50f3869d4 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Zares želite namestiti to datoteko za jezik <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Prišlo je do napake"</string>
<string name="button_default" msgid="3988017840431881491">"Privzeto"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Jezik in vnos"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Izbira načina vnosa"</string>
</resources>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index 0a9743747..2d13db099 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Желите ли стварно да инсталирате ову датотеку за <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Дошло је до грешке"</string>
<string name="button_default" msgid="3988017840431881491">"Подразумевано"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Језик и унос"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Избор метода уноса"</string>
</resources>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index dd8af36fb..608caad17 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Vill du verkligen installera filen för <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Ett fel uppstod"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Språk &amp; inmatning"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Välj inmatningsmetod"</string>
</resources>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index e8a32bfc0..104a5d42e 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Isakinishe faili hii kwa <xliff:g id="LOCALE_NAME">%s</xliff:g> kweli?"</string>
<string name="error" msgid="8940763624668513648">"Kulikuwa na hitilafu"</string>
<string name="button_default" msgid="3988017840431881491">"Chaguo-msingi"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Lugha na uingizaji"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Chagua mbinu ya kuingiza data"</string>
</resources>
diff --git a/java/res/values-sw600dp-land/setup-dimens.xml b/java/res/values-sw600dp-land/setup-dimens.xml
new file mode 100644
index 000000000..9aea21423
--- /dev/null
+++ b/java/res/values-sw600dp-land/setup-dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <dimen name="setup_title_text_size">64sp</dimen>
+ <dimen name="setup_horizontal_padding">96dp</dimen>
+</resources>
diff --git a/java/res/values-sw768dp-land/setup-dimens.xml b/java/res/values-sw768dp-land/setup-dimens.xml
new file mode 100644
index 000000000..0d2af17e3
--- /dev/null
+++ b/java/res/values-sw768dp-land/setup-dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <dimen name="setup_title_text_size">64sp</dimen>
+ <dimen name="setup_horizontal_padding">192dp</dimen>
+</resources>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 008e3e2ea..1db5e91cd 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"ติดตั้งไฟล์นี้สำหรับ <xliff:g id="LOCALE_NAME">%s</xliff:g> จริงๆ หรือ"</string>
<string name="error" msgid="8940763624668513648">"เกิดข้อผิดพลาด"</string>
<string name="button_default" msgid="3988017840431881491">"ค่าเริ่มต้น"</string>
+ <string name="language_settings" msgid="1671153053201809031">"ภาษาและการป้อนข้อมูล"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"เลือกวิธีการป้อนข้อมูล"</string>
</resources>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index ae29e6af3..adf0a1982 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"I-install talaga ang file na ito para sa <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Nagkaroon ng error"</string>
<string name="button_default" msgid="3988017840431881491">"Default"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Wika at input"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Pumili ng pamamaraan ng pag-input"</string>
</resources>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index eb8f2dc1f..fd80fea5b 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"<xliff:g id="LOCALE_NAME">%s</xliff:g> için bu dosya gerçekten yüklensin mi?"</string>
<string name="error" msgid="8940763624668513648">"Bir hata oluştu"</string>
<string name="button_default" msgid="3988017840431881491">"Varsayılan"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Dil ve giriş"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Giriş yöntemini seçin"</string>
</resources>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 5eaad63d2..2e2fdfcff 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Справді встановити цей файл для такої мови: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Сталася помилка"</string>
<string name="button_default" msgid="3988017840431881491">"За умовчанням"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Мова та введення"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Вибрати метод введення"</string>
</resources>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index fd778d5ee..6721980cf 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Thực sự cài đặt tệp này cho <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
<string name="error" msgid="8940763624668513648">"Đã xảy ra lỗi"</string>
<string name="button_default" msgid="3988017840431881491">"Mặc định"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Ngôn ngữ và phương thức nhập"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Chọn phương thức nhập"</string>
</resources>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index bc94938aa..ebb6b9161 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"确定要为<xliff:g id="LOCALE_NAME">%s</xliff:g>安装此文件吗?"</string>
<string name="error" msgid="8940763624668513648">"出现错误"</string>
<string name="button_default" msgid="3988017840431881491">"默认"</string>
+ <string name="language_settings" msgid="1671153053201809031">"语言和输入法"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"选择输入法"</string>
</resources>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 0bbd30b8f..7d4ea72eb 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"準備為<xliff:g id="LOCALE_NAME">%s</xliff:g>版本安裝這個檔案嗎?"</string>
<string name="error" msgid="8940763624668513648">"發生錯誤"</string>
<string name="button_default" msgid="3988017840431881491">"預設"</string>
+ <string name="language_settings" msgid="1671153053201809031">"語言與輸入設定"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"選擇輸入法"</string>
</resources>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index 5848b955d..29ed595b7 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -157,4 +157,6 @@
<string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Ufuna ukufakela i-<xliff:g id="LOCALE_NAME">%s</xliff:g> leli fayela ngokweqiniso?"</string>
<string name="error" msgid="8940763624668513648">"Kube nephutha"</string>
<string name="button_default" msgid="3988017840431881491">"Okuzenzakalelayo"</string>
+ <string name="language_settings" msgid="1671153053201809031">"Ulimi nokokufakwayo"</string>
+ <string name="select_input_method" msgid="4301602374609275003">"Khetha indlela yokufaka"</string>
</resources>
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
index c0ea321ce..8a8049f1f 100644
--- a/java/res/values/colors.xml
+++ b/java/res/values/colors.xml
@@ -53,4 +53,9 @@
<color name="spacebar_text_color_ics">#FFC0C0C0</color>
<color name="spacebar_text_shadow_color_ics">#80000000</color>
<color name="typed_word_color_ics">@color/highlight_color_ics</color>
+ <!-- Color resources for setup wizard and tutorial -->
+ <color name="setup_background">#FFEBEBEB</color>
+ <color name="setup_text_dark">#FF707070</color>
+ <color name="setup_text_action">@android:color/holo_blue_light</color>
+ <color name="setup_step_background">@android:color/background_light</color>
</resources>
diff --git a/java/res/values/setup-dimens.xml b/java/res/values/setup-dimens.xml
new file mode 100644
index 000000000..007906dc0
--- /dev/null
+++ b/java/res/values/setup-dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <dimen name="setup_title_text_size">46sp</dimen>
+ <dimen name="setup_horizontal_padding">16dp</dimen>
+</resources>
diff --git a/java/res/values/setup-styles.xml b/java/res/values/setup-styles.xml
new file mode 100644
index 000000000..cfc689a78
--- /dev/null
+++ b/java/res/values/setup-styles.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="setupTitleStyle">
+ <item name="android:textColor">@color/setup_text_dark</item>
+ <item name="android:textSize">@dimen/setup_title_text_size</item>
+ </style>
+ <style name="setupStepBulletStyle">
+ <item name="android:textColor">@color/setup_text_dark</item>
+ <item name="android:textSize">22sp</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_weight">1.0</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center_horizontal</item>
+ </style>
+ <style name="setupStepTitleStyle">
+ <item name="android:background">@color/setup_step_background</item>
+ <item name="android:textColor">@color/setup_text_dark</item>
+ <item name="android:textSize">22sp</item>
+ </style>
+ <style name="setupStepInstructionStyle">
+ <item name="android:background">@color/setup_step_background</item>
+ <item name="android:textColor">@color/setup_text_dark</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+ <style name="setupStepActionLabelStyle">
+ <item name="android:background">@color/setup_step_background</item>
+ <item name="android:textColor">@color/setup_text_action</item>
+ <item name="android:textSize">18sp</item>
+ </style>
+</resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index ee79b450e..e89174b02 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -223,6 +223,29 @@
<!-- Spoken feedback after changing to the shifted phone dialer (symbols) keyboard. -->
<string name="spoken_description_mode_phone_shift">Phone symbols mode</string>
+ <!-- Spoken feedback when the keyboard is hidden. -->
+ <string name="announce_keyboard_hidden">Keyboard hidden</string>
+ <!-- Spoken feedback when the keyboard mode changes. -->
+ <string name="announce_keyboard_mode">Showing <xliff:g id="mode" example="email">%s</xliff:g> keyboard</string>
+ <!-- Description of the keyboard mode for entering dates. -->
+ <string name="keyboard_mode_date">date</string>
+ <!-- Description of the keyboard mode for entering dates and times. -->
+ <string name="keyboard_mode_date_time">date and time</string>
+ <!-- Description of the keyboard mode for entering email addresses. -->
+ <string name="keyboard_mode_email">email</string>
+ <!-- Description of the keyboard mode for entering text messages. -->
+ <string name="keyboard_mode_im">messaging</string>
+ <!-- Description of the keyboard mode for entering numbers. -->
+ <string name="keyboard_mode_number">number</string>
+ <!-- Description of the keyboard mode for entering phone numbers. -->
+ <string name="keyboard_mode_phone">phone</string>
+ <!-- Description of the keyboard mode for entering generic text. -->
+ <string name="keyboard_mode_text">text</string>
+ <!-- Description of the keyboard mode for entering times. -->
+ <string name="keyboard_mode_time">time</string>
+ <!-- Description of the keyboard mode for entering URLs. -->
+ <string name="keyboard_mode_url">URL</string>
+
<!-- Preferences item for enabling speech input -->
<string name="voice_input">Voice input key</string>
@@ -408,4 +431,32 @@
<!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] -->
<string name="button_default">Default</string>
+
+ <!-- TODO: Remove translatable="false" once wordings are finalized. -->
+ <!-- Title of the setup wizard. [CHAR LIMT=40] -->
+ <string name="setup_title" translatable="false">"Installing <xliff:g id="application_name">%s</xliff:g>"</string>
+ <!-- Ordinal number of the 1st step in the setup wizard. [CHAR LIMIT=5] -->
+ <string name="setup_step1_bullet" translatable="false">1</string>
+ <!-- Title of the 1st step in the setup wizard. [CHAR LIMIT=64] -->
+ <string name="setup_step1_title" translatable="false">"Enable <xliff:g id="application_name">%s</xliff:g> in settings."</string>
+ <!-- Detailed instruction of the 1st step in the setup wizard. [CHAR LIMIT=80] -->
+ <string name="setup_step1_instruction" translatable="false">"For security, please check \"<xliff:g id="application_name">%s</xliff:g>\""</string>
+ <!-- Ordinal number of the 2nd step in the setup wizard. [CHAR LIMIT=5] -->
+ <string name="setup_step2_bullet" translatable="false">2</string>
+ <!-- Title of the 2nd step in the setup wizard. [CHAR LIMIT=64] -->
+ <string name="setup_step2_title" translatable="false">"Switch to <xliff:g id="application_name">%s</xliff:g>."</string>
+ <!-- Detailed instruction of the 2nd step in the setup wizard. [CHAR LIMIT=80] -->
+ <string name="setup_step2_instruction" translatable="false">"Now that you've enabled <xliff:g id="application_name">%s</xliff:g>, you can switch to it."</string>
+ <!-- Ordinal number of the 3rd step in the setup wizard. [CHAR LIMIT=5] -->
+ <string name="setup_step3_bullet" translatable="false">3</string>
+ <!-- Title of the 3rd step in the setup wizard. [CHAR LIMIT=64] -->
+ <string name="setup_step3_title" translatable="false">"Congratulations, you're all set!"</string>
+ <!-- Detailed instruction of the 3rd step in the setup wizard. [CHAR LIMIT=80] -->
+ <string name="setup_step3_instruction" translatable="false">Configure additional languages</string>
+ <!-- Title of the Language & input settings. This should be aligned with msgid="5292716747264442359" -->
+ <string name="language_settings">Language &amp; input</string>
+ <!-- Title of the Input method picker. This should be aligned with msgid="4653387336791222978" -->
+ <string name="select_input_method">Choose input method</string>
+ <!-- Option to show setup wizard icon. [CHAR LIMIT=30]-->
+ <string name="show_setup_wizard_icon" translatable="false">Show setup wizard icon</string>
</resources>
diff --git a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
index a0e5cbb92..0e3013afe 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
@@ -28,19 +28,9 @@
<Key
latin:keyLabel=";"
latin:moreKeys=":" />
- <!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK
- U+2019: "’" RIGHT SINGLE QUOTATION MARK
- U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- U+201C: "“" LEFT DOUBLE QUOTATION MARK
- U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
- <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- moreKeys="!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x2018;,&#x2019;,&#x201A;,&#x201B;" -->
<Key
latin:keyLabel="\'"
- latin:moreKeys="!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x2018;,&#x2019;,&#x201A;,&#x201B;,&quot;" />
+ latin:moreKeys="!fixedColumnOrder!3,!text/double_quotes,!text/single_quotes" />
</case>
<default>
<Key
@@ -48,20 +38,10 @@
latin:keyHintLabel=":"
latin:moreKeys=":"
latin:keyStyle="hasShiftedLetterHintStyle" />
- <!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK
- U+2019: "’" RIGHT SINGLE QUOTATION MARK
- U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- U+201C: "“" LEFT DOUBLE QUOTATION MARK
- U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
- <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- moreKeys="!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x2018;,&#x2019;,&#x201A;,&#x201B;" -->
<Key
latin:keyLabel="\'"
latin:keyHintLabel="&quot;"
- latin:moreKeys="!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x2018;,&#x2019;,&#x201A;,&#x201B;,&quot;"
+ latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,&quot;,!text/single_quotes"
latin:keyStyle="hasShiftedLetterHintStyle" />
</default>
</switch>
diff --git a/java/res/xml-v16/key_hindi1_shift.xml b/java/res/xml-v16/key_hindi1_shift.xml
new file mode 100644
index 000000000..19b964367
--- /dev/null
+++ b/java/res/xml-v16/key_hindi1_shift.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0903: "ः" DEVANAGARI SIGN VISARGA -->
+ <Key
+ latin:keyLabel="&#x0903;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/key_hindi3_right.xml b/java/res/xml-v16/key_hindi3_right.xml
new file mode 100644
index 000000000..232810f98
--- /dev/null
+++ b/java/res/xml-v16/key_hindi3_right.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+093C: "़" DEVANAGARI SIGN NUKTA
+ U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP
+ U+0970: "॰" DEVANAGARI ABBREVIATION SIGN
+ U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <Key
+ latin:keyLabel="&#x093C;"
+ latin:moreKeys="&#x097D;,&#x0970;,&#x093D;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/key_hindi3_shift_left.xml b/java/res/xml-v16/key_hindi3_shift_left.xml
new file mode 100644
index 000000000..1eb1768a1
--- /dev/null
+++ b/java/res/xml-v16/key_hindi3_shift_left.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU
+ U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E -->
+ <Key
+ latin:keyLabel="&#x0901;"
+ latin:moreKeys="&#x0945;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/key_hindi3_shift_right.xml b/java/res/xml-v16/key_hindi3_shift_right.xml
new file mode 100644
index 000000000..0f26cb55c
--- /dev/null
+++ b/java/res/xml-v16/key_hindi3_shift_right.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R
+ U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR -->
+ <Key
+ latin:keyLabel="&#x0943;"
+ latin:moreKeys="&#x0944;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/keys_hindi1_left5.xml b/java/res/xml-v16/keys_hindi1_left5.xml
new file mode 100644
index 000000000..e3ad299ff
--- /dev/null
+++ b/java/res/xml-v16/keys_hindi1_left5.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+094C: "ौ" DEVANAGARI VOWEL SIGN AU
+ U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA
+ U+0967: "१" DEVANAGARI DIGIT ONE -->
+ <Key
+ latin:keyLabel="&#x094C;"
+ latin:moreKeys="&#x094C;&#x0902;,%"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="&#x0967;,1"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0948: "ै" DEVANAGARI VOWEL SIGN AI
+ U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA
+ U+0968: "२" DEVANAGARI DIGIT TWO -->
+ <Key
+ latin:keyLabel="&#x0948;"
+ latin:moreKeys="&#x0948;&#x0902;,%"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="&#x0968;,2"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+093E: "ा" DEVANAGARI VOWEL SIGN AA
+ U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA
+ U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU
+ U+0969: "३" DEVANAGARI DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#x093E;"
+ latin:moreKeys="&#x093E;&#x0902;,&#x093E;&#x0901;,%"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="&#x0969;,3"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0940: "ी" DEVANAGARI VOWEL SIGN II
+ U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA
+ U+096A: "४" DEVANAGARI DIGIT FOUR -->
+ <Key
+ latin:keyLabel="&#x0940;"
+ latin:moreKeys="&#x0940;&#x0902;,%"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="&#x096A;,4"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0942: "ू" DEVANAGARI VOWEL SIGN UU
+ U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA
+ U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU
+ U+096B: "५" DEVANAGARI DIGIT FIVE -->
+ <Key
+ latin:keyLabel="&#x0942;"
+ latin:moreKeys="&#x0942;&#x0902;,&#x0942;&#x0901;,%"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="&#x096B;,5"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/keys_hindi2_left5.xml b/java/res/xml-v16/keys_hindi2_left5.xml
new file mode 100644
index 000000000..05c4f57e9
--- /dev/null
+++ b/java/res/xml-v16/keys_hindi2_left5.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+094B: "ो" DEVANAGARI VOWEL SIGN O
+ U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA
+ U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O
+ U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O -->
+ <Key
+ latin:keyLabel="&#x094B;"
+ latin:moreKeys="&#x094B;&#x0902;,&#x0949;,&#x094A;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0947: "े" DEVANAGARI VOWEL SIGN E
+ U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA -->
+ <Key
+ latin:keyLabel="&#x0947;"
+ latin:moreKeys="&#x0947;&#x0902;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+094D: "्" DEVANAGARI SIGN VIRAMA -->
+ <Key
+ latin:keyLabel="&#x094D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+093F: "ि" DEVANAGARI VOWEL SIGN I
+ U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA -->
+ <Key
+ latin:keyLabel="&#x093F;"
+ latin:moreKeys="&#x093F;&#x0902;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0941: "ु" DEVANAGARI VOWEL SIGN U
+ U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA
+ U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU -->
+ <Key
+ latin:keyLabel="&#x0941;"
+ latin:moreKeys="&#x0941;&#x0902;,&#x0941;&#x0901;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/keys_hindi3_left2.xml b/java/res/xml-v16/keys_hindi3_left2.xml
new file mode 100644
index 000000000..9474c1763
--- /dev/null
+++ b/java/res/xml-v16/keys_hindi3_left2.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O -->
+ <Key
+ latin:keyLabel="&#x0949;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
+ <Key
+ latin:keyLabel="&#x0902;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml/key_hindi1_shift.xml b/java/res/xml/key_hindi1_shift.xml
new file mode 100644
index 000000000..0db5ae9af
--- /dev/null
+++ b/java/res/xml/key_hindi1_shift.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0903: "ः" DEVANAGARI SIGN VISARGA -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0903;"
+ latin:code="0x0903"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/key_hindi3_right.xml b/java/res/xml/key_hindi3_right.xml
new file mode 100644
index 000000000..5a97355f6
--- /dev/null
+++ b/java/res/xml/key_hindi3_right.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093C: "़" DEVANAGARI SIGN NUKTA
+ U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP
+ U+0970: "॰" DEVANAGARI ABBREVIATION SIGN
+ U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x093C;"
+ latin:code="0x093C"
+ latin:moreKeys="&#x25CC;&#x097D;|&#x097D;,&#x25CC;&#x0970;|&#x0970;,&#x25CC;&#x093D;|&#x093D;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/key_hindi3_shift_left.xml b/java/res/xml/key_hindi3_shift_left.xml
new file mode 100644
index 000000000..c5e2f1386
--- /dev/null
+++ b/java/res/xml/key_hindi3_shift_left.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU
+ U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0901;"
+ latin:code="0x0901"
+ latin:moreKeys="&#x25CC;&#x0945;|&#x0945;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/key_hindi3_shift_right.xml b/java/res/xml/key_hindi3_shift_right.xml
new file mode 100644
index 000000000..0da116ab8
--- /dev/null
+++ b/java/res/xml/key_hindi3_shift_right.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R
+ U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0943;"
+ latin:code="0x0943"
+ latin:moreKeys="&#x25CC;&#x0944;|&#x0944;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml
index 61a515bad..5976e95db 100644
--- a/java/res/xml/key_styles_enter.xml
+++ b/java/res/xml/key_styles_enter.xml
@@ -104,7 +104,7 @@
latin:parentStyle="defaultEnterKeyStyle" />
<key-style
latin:styleName="defaultActionEnterKeyStyle"
- latin:code="!code/key_action_enter"
+ latin:code="!code/key_enter"
latin:keyIcon="!icon/undefined"
latin:backgroundType="action"
latin:parentStyle="defaultEnterKeyStyle" />
diff --git a/java/res/xml/keys_hindi1_left5.xml b/java/res/xml/keys_hindi1_left5.xml
new file mode 100644
index 000000000..8757afeaf
--- /dev/null
+++ b/java/res/xml/keys_hindi1_left5.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+094C: "ौ" DEVANAGARI VOWEL SIGN AU
+ U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA
+ U+0967: "१" DEVANAGARI DIGIT ONE -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x094C;"
+ latin:code="0x094C"
+ latin:moreKeys="&#x25CC;&#x094C;&#x0902;|&#x094C;&#x0902;,%"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="&#x0967;,1"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0948: "ै" DEVANAGARI VOWEL SIGN AI
+ U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA
+ U+0968: "२" DEVANAGARI DIGIT TWO -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0948;"
+ latin:code="0x0948"
+ latin:moreKeys="&#x25CC;&#x0948;&#x0902;|&#x0948;&#x0902;,%"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="&#x0968;,2"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093E: "ा" DEVANAGARI VOWEL SIGN AA
+ U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA
+ U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU
+ U+0969: "३" DEVANAGARI DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x093E;"
+ latin:code="0x093E"
+ latin:moreKeys="&#x25CC;&#x093E;&#x0902;|&#x093E;&#x0902;,&#x25CC;&#x093E;&#x0901;|&#x093E;&#x0901;,%"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="&#x0969;,3"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0940: "ी" DEVANAGARI VOWEL SIGN II
+ U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA
+ U+096A: "४" DEVANAGARI DIGIT FOUR -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0940;"
+ latin:code="0x0940"
+ latin:moreKeys="&#x25CC;&#x0940;&#x0902;|&#x0940;&#x0902;,%"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="&#x096A;,4"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0942: "ू" DEVANAGARI VOWEL SIGN UU
+ U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA
+ U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU
+ U+096B: "५" DEVANAGARI DIGIT FIVE -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0942;"
+ latin:code="0x0942"
+ latin:moreKeys="&#x25CC;&#x0942;&#x0902;|&#x0942;&#x0902;,&#x25CC;&#x0942;&#x0901;|&#x0942;&#x0901;,%"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="&#x096B;,5"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/keys_hindi2_left5.xml b/java/res/xml/keys_hindi2_left5.xml
new file mode 100644
index 000000000..4c3a5e051
--- /dev/null
+++ b/java/res/xml/keys_hindi2_left5.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+094B: "ो" DEVANAGARI VOWEL SIGN O
+ U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA
+ U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O
+ U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x094B;"
+ latin:code="0x094B"
+ latin:moreKeys="&#x25CC;&#x094B;&#x0902;|&#x094B;&#x0902;,&#x25CC;&#x0949;,&#x094A;|&#x0949;,&#x094A;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0947: "े" DEVANAGARI VOWEL SIGN E
+ U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0947;"
+ latin:code="0x0947"
+ latin:moreKeys="&#x25CC;&#x0947;&#x0902;|&#x0947;&#x0902;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+094D: "्" DEVANAGARI SIGN VIRAMA -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x094D;"
+ latin:code="0x094D"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093F: "ि" DEVANAGARI VOWEL SIGN I
+ U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA -->
+ <Key
+ latin:keyLabel="&#x093F;&#x25CC;"
+ latin:code="0x093F"
+ latin:moreKeys="&#x093F;&#x25CC;&#x0902;|&#x093F;&#x0902;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0941: "ु" DEVANAGARI VOWEL SIGN U
+ U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA
+ U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0941;"
+ latin:code="0x0941"
+ latin:moreKeys="&#x25CC;&#x0941;&#x0902;|&#x0941;&#x0902;,&#x25CC;&#x0941;&#x0901;|&#x0941;&#x0901;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/keys_hindi3_left2.xml b/java/res/xml/keys_hindi3_left2.xml
new file mode 100644
index 000000000..4f1ad16ef
--- /dev/null
+++ b/java/res/xml/keys_hindi3_left2.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of Hindi. The files named res/xml/{key,keys}_hindi*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0949;"
+ latin:code="0x0949"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
+ <Key
+ latin:keyLabel="&#x25CC;&#x0902;"
+ latin:code="0x0902"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/keys_pcqwerty3_right2.xml b/java/res/xml/keys_pcqwerty3_right2.xml
index fd9d3b8b0..aa150afb3 100644
--- a/java/res/xml/keys_pcqwerty3_right2.xml
+++ b/java/res/xml/keys_pcqwerty3_right2.xml
@@ -30,25 +30,15 @@
latin:moreKeys=":" />
<Key
latin:keyLabel="\'"
- latin:moreKeys="&quot;" />
+ latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,&quot;,!text/single_quotes" />
</case>
<!-- keyboardLayoutSetElement="alphabet*Shifted|symbols*" -->
<default>
<Key
latin:keyLabel=":" />
- <!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK
- U+2019: "’" RIGHT SINGLE QUOTATION MARK
- U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- U+201C: "“" LEFT DOUBLE QUOTATION MARK
- U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
- <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- moreKeys="!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x2018;,&#x2019;,&#x201A;,&#x201B;" -->
<Key
latin:keyLabel="&quot;"
- latin:moreKeys="!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x2018;,&#x2019;,&#x201A;,&#x201B;" />
+ latin:moreKeys="!fixedColumnOrder!3,!text/double_quotes,!text/single_quotes" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 5ed0bb029..e5fef8834 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -60,7 +60,11 @@
<intent
android:action="android.intent.action.MAIN"
android:targetPackage="@string/dictionary_pack_package_name"
- android:targetClass="@string/dictionary_pack_settings_activity" />
+ android:targetClass="@string/dictionary_pack_settings_activity">
+ <extra
+ android:name="clientId"
+ android:value="@string/dictionary_pack_client_id" />
+ </intent>
</PreferenceScreen>
<ListPreference
android:key="auto_correction_threshold"
@@ -141,7 +145,7 @@
android:fragment="com.android.inputmethod.latin.AdditionalSubtypeSettings"
android:key="custom_input_styles"
android:title="@string/custom_input_styles_title" />
- <!-- Values for popup dismiss delay are added programatically -->
+ <!-- Values for popup dismiss delay are added programmatically -->
<CheckBoxPreference
android:key="pref_sliding_key_input_preview"
android:title="@string/sliding_key_input_preview"
@@ -167,6 +171,11 @@
android:key="pref_keypress_sound_volume"
android:title="@string/prefs_keypress_sound_volume_settings"
latin:maxValue="100" /> <!-- percent -->
+ <!-- The show setup wizard icon settings shouldn't be persistent and the default value
+ is added programmatically. -->
+ <CheckBoxPreference
+ android:key="pref_show_setup_wizard_icon"
+ android:title="@string/show_setup_wizard_icon" />
</PreferenceScreen>
<PreferenceScreen
android:key="debug_settings"
diff --git a/java/res/xml/row_symbols_shift4.xml b/java/res/xml/row_symbols_shift4.xml
index 1bfb5ecd1..99a685c45 100644
--- a/java/res/xml/row_symbols_shift4.xml
+++ b/java/res/xml/row_symbols_shift4.xml
@@ -27,13 +27,11 @@
<Key
latin:keyStyle="toAlphaKeyStyle"
latin:keyWidth="15%p" />
- <!-- U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
- <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
- <!-- latin:keyLabelFlags="hasPopupHint" -->
- <!-- latin:moreKeys="&#x201F;" -->
- <!-- U+201E: "„" DOUBLE LOW-9 QUOTATION MARK -->
+ <!-- U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+ U+201E: "„" DOUBLE LOW-9 QUOTATION MARK -->
<Key
latin:keyLabel="&#x201E;"
+ latin:moreKeys="&#x201A;"
latin:backgroundType="functional" />
<include
latin:keyXPos="25%p"
diff --git a/java/res/xml/rowkeys_hindi1.xml b/java/res/xml/rowkeys_hindi1.xml
index 11208045c..a761a6c69 100644
--- a/java/res/xml/rowkeys_hindi1.xml
+++ b/java/res/xml/rowkeys_hindi1.xml
@@ -61,10 +61,11 @@
<Key
latin:keyLabel="&#x092D;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0903: "ः" DEVANAGARI SIGN VISARGA -->
- <Key
- latin:keyLabel="&#x0903;"
- latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of Hindi, different set of
+ Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_hindi1_shift" />
<!-- U+0918: "घ" DEVANAGARI LETTER GHA -->
<Key
latin:keyLabel="&#x0918;"
@@ -86,53 +87,11 @@
latin:keyLabelFlags="fontNormal" />
</case>
<default>
- <!-- U+094C: "ौ" DEVANAGARI VOWEL SIGN AU
- U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA
- U+0967: "१" DEVANAGARI DIGIT ONE -->
- <Key
- latin:keyLabel="&#x094C;"
- latin:moreKeys="&#x094C;&#x0902;,%"
- latin:keyHintLabel="1"
- latin:additionalMoreKeys="&#x0967;,1"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0948: "ै" DEVANAGARI VOWEL SIGN AI
- U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA
- U+0968: "२" DEVANAGARI DIGIT TWO -->
- <Key
- latin:keyLabel="&#x0948;"
- latin:moreKeys="&#x0948;&#x0902;,%"
- latin:keyHintLabel="2"
- latin:additionalMoreKeys="&#x0968;,2"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+093E: "ा" DEVANAGARI VOWEL SIGN AA
- U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA
- U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU
- U+0969: "३" DEVANAGARI DIGIT THREE -->
- <Key
- latin:keyLabel="&#x093E;"
- latin:moreKeys="&#x093E;&#x0902;,&#x093E;&#x0901;,%"
- latin:keyHintLabel="3"
- latin:additionalMoreKeys="&#x0969;,3"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0940: "ी" DEVANAGARI VOWEL SIGN II
- U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA
- U+096A: "४" DEVANAGARI DIGIT FOUR -->
- <Key
- latin:keyLabel="&#x0940;"
- latin:moreKeys="&#x0940;&#x0902;,%"
- latin:keyHintLabel="4"
- latin:additionalMoreKeys="&#x096A;,4"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0942: "ू" DEVANAGARI VOWEL SIGN UU
- U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA
- U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU
- U+096B: "५" DEVANAGARI DIGIT FIVE -->
- <Key
- latin:keyLabel="&#x0942;"
- latin:moreKeys="&#x0942;&#x0902;,&#x0942;&#x0901;,%"
- latin:keyHintLabel="5"
- latin:additionalMoreKeys="&#x096B;,5"
- latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of Hindi, different set of
+ Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keys_hindi1_left5" />
<!-- U+092C: "ब" DEVANAGARI LETTER BA
U+092C/U+0952: "ब॒" DEVANAGARI LETTER BA/DEVANAGARI STRESS SIGN ANUDATTA -->
<Key
diff --git a/java/res/xml/rowkeys_hindi2.xml b/java/res/xml/rowkeys_hindi2.xml
index e7c67dbe7..9545b840f 100644
--- a/java/res/xml/rowkeys_hindi2.xml
+++ b/java/res/xml/rowkeys_hindi2.xml
@@ -96,37 +96,11 @@
latin:keyLabelFlags="fontNormal" />
</case>
<default>
- <!-- U+094B: "ो" DEVANAGARI VOWEL SIGN O
- U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA
- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O
- U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O -->
- <Key
- latin:keyLabel="&#x094B;"
- latin:moreKeys="&#x094B;&#x0902;,&#x0949;,&#x094A;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0947: "े" DEVANAGARI VOWEL SIGN E
- U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x0947;"
- latin:moreKeys="&#x0947;&#x0902;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+094D: "्" DEVANAGARI SIGN VIRAMA -->
- <Key
- latin:keyLabel="&#x094D;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+093F: "ि" DEVANAGARI VOWEL SIGN I
- U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x093F;"
- latin:moreKeys="&#x093F;&#x0902;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0941: "ु" DEVANAGARI VOWEL SIGN U
- U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA
- U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU -->
- <Key
- latin:keyLabel="&#x0941;"
- latin:moreKeys="&#x0941;&#x0902;,&#x0941;&#x0901;"
- latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of Hindi, different set of
+ Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keys_hindi2_left5" />
<!-- U+092A: "प" DEVANAGARI LETTER PA -->
<Key
latin:keyLabel="&#x092A;"
diff --git a/java/res/xml/rowkeys_hindi3.xml b/java/res/xml/rowkeys_hindi3.xml
index ebbff3e33..3014907ed 100644
--- a/java/res/xml/rowkeys_hindi3.xml
+++ b/java/res/xml/rowkeys_hindi3.xml
@@ -29,12 +29,11 @@
<Key
latin:keyLabel="&#x0911;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU
- U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E-->
- <Key
- latin:keyLabel="&#x0901;"
- latin:moreKeys="&#x0945;"
- latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of Hindi, different set of
+ Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_hindi3_shift_left" />
<!-- U+0923: "ण" DEVANAGARI LETTER NNA -->
<Key
latin:keyLabel="&#x0923;"
@@ -56,26 +55,22 @@
<Key
latin:keyLabel="&#x0937;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R
- U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR -->
- <Key
- latin:keyLabel="&#x0943;"
- latin:moreKeys="&#x0944;"
- latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of Hindi, different set of
+ Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_hindi3_shift_right" />
<!-- U+091E: "ञ" DEVANAGARI LETTER NYA -->
<Key
latin:keyLabel="&#x091E;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
- <!-- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O -->
- <Key
- latin:keyLabel="&#x0949;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x0902;"
- latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of Hindi, different set of
+ Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keys_hindi3_left2" />
<!-- U+092E: "म" DEVANAGARI LETTER MA
U+0950: "ॐ" DEVANAGARI OM -->
<Key
@@ -111,14 +106,11 @@
latin:keyLabel="&#x092F;"
latin:moreKeys="&#x095F;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+093C: "़" DEVANAGARI SIGN NUKTA
- U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP
- U+0970: "॰" DEVANAGARI ABBREVIATION SIGN
- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
- <Key
- latin:keyLabel="&#x093C;"
- latin:moreKeys="&#x097D;,&#x0970;,&#x093D;"
- latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of Hindi, different set of
+ Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_hindi3_right" />
</default>
</switch>
</merge>
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index bf1cea9c3..ee52de1d1 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -80,16 +80,24 @@ public final class AccessibilityUtils {
}
/**
+ * Returns {@code true} if accessibility is enabled. Currently, this means
+ * that the kill switch is off and system accessibility is turned on.
+ *
+ * @return {@code true} if accessibility is enabled.
+ */
+ public boolean isAccessibilityEnabled() {
+ return ENABLE_ACCESSIBILITY && mAccessibilityManager.isEnabled();
+ }
+
+ /**
* Returns {@code true} if touch exploration is enabled. Currently, this
* means that the kill switch is off, the device supports touch exploration,
- * and a spoken feedback service is turned on.
+ * and system accessibility is turned on.
*
* @return {@code true} if touch exploration is enabled.
*/
public boolean isTouchExplorationEnabled() {
- return ENABLE_ACCESSIBILITY
- && mAccessibilityManager.isEnabled()
- && mAccessibilityManager.isTouchExplorationEnabled();
+ return isAccessibilityEnabled() && mAccessibilityManager.isTouchExplorationEnabled();
}
/**
@@ -113,6 +121,7 @@ public final class AccessibilityUtils {
*
* @return {@code true} if the device should obscure password characters.
*/
+ @SuppressWarnings("deprecation")
public boolean shouldObscureInput(final EditorInfo editorInfo) {
if (editorInfo == null) return false;
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index d05fd9eb5..e6b44120f 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -22,8 +22,11 @@ import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
@@ -35,6 +38,21 @@ import com.android.inputmethod.latin.R;
public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy();
+ /** Map of keyboard modes to resource IDs. */
+ private static final SparseIntArray KEYBOARD_MODE_RES_IDS = new SparseIntArray();
+
+ static {
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_DATE, R.string.keyboard_mode_date);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_DATETIME, R.string.keyboard_mode_date_time);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_EMAIL, R.string.keyboard_mode_email);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_IM, R.string.keyboard_mode_im);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_NUMBER, R.string.keyboard_mode_number);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_PHONE, R.string.keyboard_mode_phone);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_TEXT, R.string.keyboard_mode_text);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_TIME, R.string.keyboard_mode_time);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_URL, R.string.keyboard_mode_url);
+ }
+
private InputMethodService mInputMethod;
private MainKeyboardView mView;
private AccessibilityEntityProvider mAccessibilityNodeProvider;
@@ -85,11 +103,75 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
mAccessibilityNodeProvider.setView(view);
}
+ /**
+ * Called when the keyboard layout changes.
+ * <p>
+ * <b>Note:</b> This method will be called even if accessibility is not
+ * enabled.
+ */
public void setKeyboard() {
- if (mAccessibilityNodeProvider == null) {
+ if (mAccessibilityNodeProvider != null) {
+ mAccessibilityNodeProvider.setKeyboard();
+ }
+
+ // Since this method is called even when accessibility is off, make sure
+ // to check the state before announcing anything.
+ if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
+ announceKeyboardMode();
+ }
+ }
+
+ /**
+ * Called when the keyboard is hidden and accessibility is enabled.
+ */
+ public void onHideWindow() {
+ announceKeyboardHidden();
+ }
+
+ /**
+ * Announces which type of keyboard is being displayed. If the keyboard type
+ * is unknown, no announcement is made.
+ */
+ private void announceKeyboardMode() {
+ final Keyboard keyboard = mView.getKeyboard();
+ final int resId = KEYBOARD_MODE_RES_IDS.get(keyboard.mId.mMode);
+ if (resId == 0) {
return;
}
- mAccessibilityNodeProvider.setKeyboard();
+
+ final Context context = mView.getContext();
+ final String keyboardMode = context.getString(resId);
+ final String text = context.getString(R.string.announce_keyboard_mode, keyboardMode);
+
+ sendWindowStateChanged(text);
+ }
+
+ /**
+ * Announces that the keyboard has been hidden.
+ */
+ private void announceKeyboardHidden() {
+ final Context context = mView.getContext();
+ final String text = context.getString(R.string.announce_keyboard_hidden);
+
+ sendWindowStateChanged(text);
+ }
+
+ /**
+ * Sends a window state change event with the specified text.
+ *
+ * @param text
+ */
+ private void sendWindowStateChanged(final String text) {
+ final AccessibilityEvent stateChange = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ mView.onInitializeAccessibilityEvent(stateChange);
+ stateChange.getText().add(text);
+ stateChange.setContentDescription(null);
+
+ final ViewParent parent = mView.getParent();
+ if (parent != null) {
+ parent.requestSendAccessibilityEvent(mView, stateChange);
+ }
}
/**
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
index ea86d98cb..05d8269b7 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -110,7 +110,9 @@ public final class KeyCodeDescriptionMapper {
return getDescriptionForShiftKey(context, keyboard);
}
- if (code == Constants.CODE_ACTION_ENTER) {
+ if (code == Constants.CODE_ENTER) {
+ // The following function returns the correct description in all action and
+ // regular enter cases, taking care of all modes.
return getDescriptionForActionKey(context, keyboard, key);
}
diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java
index 5a2b6bd2b..660029baf 100644
--- a/java/src/com/android/inputmethod/compat/CompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/CompatUtils.java
@@ -81,7 +81,7 @@ public final class CompatUtils {
try {
return constructor.newInstance(args);
} catch (Exception e) {
- Log.e(TAG, "Exception in newInstance: " + e.getClass().getSimpleName());
+ Log.e(TAG, "Exception in newInstance", e);
}
return null;
}
@@ -92,7 +92,7 @@ public final class CompatUtils {
try {
return method.invoke(receiver, args);
} catch (Exception e) {
- Log.e(TAG, "Exception in invoke: " + e.getClass().getSimpleName());
+ Log.e(TAG, "Exception in invoke", e);
}
return defaultValue;
}
@@ -103,7 +103,7 @@ public final class CompatUtils {
try {
return field.get(receiver);
} catch (Exception e) {
- Log.e(TAG, "Exception in getFieldValue: " + e.getClass().getSimpleName());
+ Log.e(TAG, "Exception in getFieldValue", e);
}
return defaultValue;
}
@@ -113,7 +113,7 @@ public final class CompatUtils {
try {
field.set(receiver, value);
} catch (Exception e) {
- Log.e(TAG, "Exception in setFieldValue: " + e.getClass().getSimpleName());
+ Log.e(TAG, "Exception in setFieldValue", e);
}
}
}
diff --git a/java/src/com/android/inputmethod/compat/IntentCompatUtils.java b/java/src/com/android/inputmethod/compat/IntentCompatUtils.java
new file mode 100644
index 000000000..df2e22fe8
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/IntentCompatUtils.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.content.Intent;
+
+public final class IntentCompatUtils {
+ // Note that Intent.ACTION_USER_INITIALIZE have been introduced in API level 17
+ // (Build.VERSION_CODE.JELLY_BEAN_MR1).
+ public static final String ACTION_USER_INITIALIZE =
+ (String)CompatUtils.getFieldValue(null, null,
+ CompatUtils.getField(Intent.class, "ACTION_USER_INITIALIZE"));
+
+ private IntentCompatUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static boolean has_ACTION_USER_INITIALIZE(final Intent intent) {
+ return ACTION_USER_INITIALIZE != null && intent != null
+ && ACTION_USER_INITIALIZE.equals(intent.getAction());
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java b/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java
new file mode 100644
index 000000000..d4f1ea830
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.graphics.drawable.Drawable;
+import android.widget.TextView;
+
+import java.lang.reflect.Method;
+
+public final class TextViewCompatUtils {
+ // Note that TextView.setCompoundDrawablesRelative(Drawable,Drawable,Drawable,Drawable) has
+ // been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+ private static final Method METHOD_setCompoundDrawablesRelative = CompatUtils.getMethod(
+ TextView.class, "setCompoundDrawablesRelative",
+ Drawable.class, Drawable.class, Drawable.class, Drawable.class);
+
+ private TextViewCompatUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static void setCompoundDrawablesRelative(final TextView textView, final Drawable start,
+ final Drawable top, final Drawable end, final Drawable bottom) {
+ if (METHOD_setCompoundDrawablesRelative == null) {
+ textView.setCompoundDrawables(start, top, end, bottom);
+ return;
+ }
+ CompatUtils.invoke(textView, null, METHOD_setCompoundDrawablesRelative,
+ start, top, end, bottom);
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
new file mode 100644
index 000000000..a8fab8855
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.view.View;
+
+import java.lang.reflect.Method;
+
+public final class ViewCompatUtils {
+ // Note that View.LAYOUT_DIRECTION_LTR and View.LAYOUT_DIRECTION_RTL have been introduced in
+ // API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+ public static final int LAYOUT_DIRECTION_LTR = (Integer)CompatUtils.getFieldValue(null, 0x0,
+ CompatUtils.getField(View.class, "LAYOUT_DIRECTION_LTR"));
+ public static final int LAYOUT_DIRECTION_RTL = (Integer)CompatUtils.getFieldValue(null, 0x1,
+ CompatUtils.getField(View.class, "LAYOUT_DIRECTION_RTL"));
+
+ // Note that View.getPaddingEnd(), View.setPaddingRelative(int,int,int,int), and
+ // View.getLayoutDirection() have been introduced in API level 17
+ // (Build.VERSION_CODE.JELLY_BEAN_MR1).
+ private static final Method METHOD_getPaddingEnd = CompatUtils.getMethod(
+ View.class, "getPaddingEnd");
+ private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
+ View.class, "setPaddingRelative",
+ Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE);
+ private static final Method METHOD_getLayoutDirection = CompatUtils.getMethod(
+ View.class, "getLayoutDirection");
+
+ private ViewCompatUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static int getPaddingEnd(final View view) {
+ if (METHOD_getPaddingEnd == null) {
+ return view.getPaddingRight();
+ }
+ return (Integer)CompatUtils.invoke(view, 0, METHOD_getPaddingEnd);
+ }
+
+ public static void setPaddingRelative(final View view, final int start, final int top,
+ final int end, final int bottom) {
+ if (METHOD_setPaddingRelative == null) {
+ view.setPadding(start, top, end, bottom);
+ return;
+ }
+ CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
+ }
+
+ public static int getLayoutDirection(final View view) {
+ if (METHOD_getLayoutDirection == null) {
+ return LAYOUT_DIRECTION_LTR;
+ }
+ return (Integer)CompatUtils.invoke(view, 0, METHOD_getLayoutDirection);
+ }
+}
diff --git a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
index a2463c20c..720d07433 100644
--- a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
+++ b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
@@ -58,11 +58,11 @@ public class HardwareKeyboardEventDecoder implements HardwareEventDecoder {
}
if (KeyEvent.KEYCODE_ENTER == keyCode) {
// The Enter key. If the Shift key is not being pressed, this should send a
- // CODE_ACTION_ENTER to trigger the action if any, or a carriage return
- // otherwise. If the Shift key is depressed, this should send a
- // CODE_SHIFT_ENTER and let Latin IME decide what to do with it.
+ // CODE_ENTER to trigger the action if any, or a carriage return otherwise. If the
+ // Shift key is being pressed, this should send a CODE_SHIFT_ENTER and let
+ // Latin IME decide what to do with it.
return Event.createCommittableEvent(keyEvent.isShiftPressed()
- ? Constants.CODE_SHIFT_ENTER : Constants.CODE_ACTION_ENTER,
+ ? Constants.CODE_SHIFT_ENTER : Constants.CODE_ENTER,
null /* next */);
}
// If not Enter, then we have a committable character. This should be committed
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 1e5af5154..d160038ad 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -519,11 +519,11 @@ public class Key implements Comparable<Key> {
// TODO: Handle "bold" here too?
if ((mLabelFlags & LABEL_FLAGS_FONT_NORMAL) != 0) {
return Typeface.DEFAULT;
- } else if ((mLabelFlags & LABEL_FLAGS_FONT_MONO_SPACE) != 0) {
+ }
+ if ((mLabelFlags & LABEL_FLAGS_FONT_MONO_SPACE) != 0) {
return Typeface.MONOSPACE;
- } else {
- return params.mTypeface;
}
+ return params.mTypeface;
}
public final int selectTextSize(final KeyDrawParams params) {
@@ -550,28 +550,51 @@ public class Key implements Comparable<Key> {
public final int selectHintTextSize(final KeyDrawParams params) {
if (hasHintLabel()) {
return params.mHintLabelSize;
- } else if (hasShiftedLetterHint()) {
+ }
+ if (hasShiftedLetterHint()) {
return params.mShiftedLetterHintSize;
- } else {
- return params.mHintLetterSize;
}
+ return params.mHintLetterSize;
}
public final int selectHintTextColor(final KeyDrawParams params) {
if (hasHintLabel()) {
return params.mHintLabelColor;
- } else if (hasShiftedLetterHint()) {
+ }
+ if (hasShiftedLetterHint()) {
return isShiftedLetterActivated() ? params.mShiftedLetterHintActivatedColor
: params.mShiftedLetterHintInactivatedColor;
- } else {
- return params.mHintLetterColor;
}
+ return params.mHintLetterColor;
}
public final int selectMoreKeyTextSize(final KeyDrawParams params) {
return hasLabelsInMoreKeys() ? params.mLabelSize : params.mLetterSize;
}
+ public final String getPreviewLabel() {
+ return isShiftedLetterActivated() ? mHintLabel : mLabel;
+ }
+
+ private boolean previewHasLetterSize() {
+ return (mLabelFlags & LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO) != 0
+ || StringUtils.codePointCount(getPreviewLabel()) == 1;
+ }
+
+ public final int selectPreviewTextSize(final KeyDrawParams params) {
+ if (previewHasLetterSize()) {
+ return params.mPreviewTextSize;
+ }
+ return params.mLetterSize;
+ }
+
+ public Typeface selectPreviewTypeface(final KeyDrawParams params) {
+ if (previewHasLetterSize()) {
+ return selectTypeface(params);
+ }
+ return Typeface.DEFAULT_BOLD;
+ }
+
public final boolean isAlignLeft() {
return (mLabelFlags & LABEL_FLAGS_ALIGN_LEFT) != 0;
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 4dab50fd8..350dc69b2 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -635,15 +635,9 @@ public class KeyboardView extends View {
invalidate(x, y, x + key.mWidth, y + key.mHeight);
}
- public void closing() {
- mInvalidateAllKeys = true;
- mKeyboard = null;
- }
-
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- closing();
freeOffscreenBuffer();
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 4d10f0e69..d37b69b00 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -811,18 +811,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
background.setState(KEY_PREVIEW_BACKGROUND_DEFAULT_STATE);
background.setAlpha(PREVIEW_ALPHA);
}
- final String label = key.isShiftedLetterActivated() ? key.mHintLabel : key.mLabel;
+ final String label = key.getPreviewLabel();
// What we show as preview should match what we show on a key top in onDraw().
if (label != null) {
// TODO Should take care of temporaryShiftLabel here.
previewText.setCompoundDrawables(null, null, null, null);
- if (StringUtils.codePointCount(label) > 1) {
- previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, drawParams.mLetterSize);
- previewText.setTypeface(Typeface.DEFAULT_BOLD);
- } else {
- previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, drawParams.mPreviewTextSize);
- previewText.setTypeface(key.selectTypeface(drawParams));
- }
+ previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ key.selectPreviewTextSize(drawParams));
+ previewText.setTypeface(key.selectPreviewTypeface(drawParams));
previewText.setText(label);
} else {
previewText.setCompoundDrawables(null, null, null,
@@ -1236,13 +1232,11 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mDrawingHandler.cancelAllMessages();
}
- @Override
public void closing() {
dismissAllKeyPreviews();
cancelAllMessages();
onDismissMoreKeysPanel();
mMoreKeysKeyboardCache.clear();
- super.closing();
}
/**
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index 9e75f8b8a..0d42ab2fe 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -174,7 +174,6 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
@Override
public boolean dismissMoreKeysPanel() {
- super.closing();
if (mController == null) return false;
return mController.onDismissMoreKeysPanel();
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
index 0ec6b0176..3e25c3b86 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
@@ -48,7 +48,6 @@ public final class KeyboardCodesSet {
"key_delete",
"key_settings",
"key_shortcut",
- "key_action_enter",
"key_action_next",
"key_action_previous",
"key_shift_enter",
@@ -85,7 +84,6 @@ public final class KeyboardCodesSet {
Constants.CODE_DELETE,
Constants.CODE_SETTINGS,
Constants.CODE_SHORTCUT,
- Constants.CODE_ACTION_ENTER,
Constants.CODE_ACTION_NEXT,
Constants.CODE_ACTION_PREVIOUS,
Constants.CODE_SHIFT_ENTER,
@@ -118,7 +116,6 @@ public final class KeyboardCodesSet {
DEFAULT[12],
DEFAULT[13],
DEFAULT[14],
- DEFAULT[15],
CODE_RIGHT_PARENTHESIS,
CODE_LEFT_PARENTHESIS,
CODE_GREATER_THAN_SIGN,
@@ -142,7 +139,7 @@ public final class KeyboardCodesSet {
};
static {
- if (DEFAULT.length != RTL.length) {
+ if (DEFAULT.length != RTL.length || DEFAULT.length != ID_TO_NAME.length) {
throw new RuntimeException("Internal inconsistency");
}
for (int i = 0; i < ID_TO_NAME.length; i++) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 493093e95..d0b382e35 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -145,94 +145,110 @@ public final class KeyboardTextsSet {
/* 40 */ "more_keys_for_cyrillic_ie",
/* 41 */ "more_keys_for_cyrillic_i",
/* 42 */ "label_to_alpha_key",
- /* 43 */ "more_keys_for_single_quote",
- /* 44 */ "more_keys_for_double_quote",
- /* 45 */ "more_keys_for_tablet_double_quote",
- /* 46 */ "more_keys_for_currency_dollar",
- /* 47 */ "keylabel_for_currency_generic",
- /* 48 */ "more_keys_for_currency_generic",
- /* 49 */ "more_keys_for_punctuation",
- /* 50 */ "more_keys_for_star",
- /* 51 */ "more_keys_for_bullet",
- /* 52 */ "more_keys_for_plus",
- /* 53 */ "more_keys_for_left_parenthesis",
- /* 54 */ "more_keys_for_right_parenthesis",
- /* 55 */ "more_keys_for_less_than",
- /* 56 */ "more_keys_for_greater_than",
- /* 57 */ "more_keys_for_arabic_diacritics",
- /* 58 */ "keyhintlabel_for_arabic_diacritics",
- /* 59 */ "keylabel_for_symbols_1",
- /* 60 */ "keylabel_for_symbols_2",
- /* 61 */ "keylabel_for_symbols_3",
- /* 62 */ "keylabel_for_symbols_4",
- /* 63 */ "keylabel_for_symbols_5",
- /* 64 */ "keylabel_for_symbols_6",
- /* 65 */ "keylabel_for_symbols_7",
- /* 66 */ "keylabel_for_symbols_8",
- /* 67 */ "keylabel_for_symbols_9",
- /* 68 */ "keylabel_for_symbols_0",
- /* 69 */ "label_to_symbol_key",
- /* 70 */ "label_to_symbol_with_microphone_key",
- /* 71 */ "additional_more_keys_for_symbols_1",
- /* 72 */ "additional_more_keys_for_symbols_2",
- /* 73 */ "additional_more_keys_for_symbols_3",
- /* 74 */ "additional_more_keys_for_symbols_4",
- /* 75 */ "additional_more_keys_for_symbols_5",
- /* 76 */ "additional_more_keys_for_symbols_6",
- /* 77 */ "additional_more_keys_for_symbols_7",
- /* 78 */ "additional_more_keys_for_symbols_8",
- /* 79 */ "additional_more_keys_for_symbols_9",
- /* 80 */ "additional_more_keys_for_symbols_0",
- /* 81 */ "more_keys_for_symbols_1",
- /* 82 */ "more_keys_for_symbols_2",
- /* 83 */ "more_keys_for_symbols_3",
- /* 84 */ "more_keys_for_symbols_4",
- /* 85 */ "more_keys_for_symbols_5",
- /* 86 */ "more_keys_for_symbols_6",
- /* 87 */ "more_keys_for_symbols_7",
- /* 88 */ "more_keys_for_symbols_8",
- /* 89 */ "more_keys_for_symbols_9",
- /* 90 */ "more_keys_for_symbols_0",
- /* 91 */ "keylabel_for_comma",
- /* 92 */ "more_keys_for_comma",
- /* 93 */ "keylabel_for_symbols_question",
- /* 94 */ "keylabel_for_symbols_semicolon",
- /* 95 */ "keylabel_for_symbols_percent",
- /* 96 */ "more_keys_for_symbols_exclamation",
- /* 97 */ "more_keys_for_symbols_question",
- /* 98 */ "more_keys_for_symbols_semicolon",
- /* 99 */ "more_keys_for_symbols_percent",
- /* 100 */ "keylabel_for_tablet_comma",
- /* 101 */ "keyhintlabel_for_tablet_comma",
- /* 102 */ "more_keys_for_tablet_comma",
- /* 103 */ "keyhintlabel_for_tablet_period",
- /* 104 */ "more_keys_for_tablet_period",
- /* 105 */ "keylabel_for_apostrophe",
- /* 106 */ "keyhintlabel_for_apostrophe",
- /* 107 */ "more_keys_for_apostrophe",
- /* 108 */ "more_keys_for_q",
- /* 109 */ "more_keys_for_x",
- /* 110 */ "keylabel_for_q",
- /* 111 */ "keylabel_for_w",
- /* 112 */ "keylabel_for_y",
- /* 113 */ "keylabel_for_x",
- /* 114 */ "keylabel_for_spanish_row2_10",
- /* 115 */ "more_keys_for_am_pm",
- /* 116 */ "settings_as_more_key",
- /* 117 */ "shortcut_as_more_key",
- /* 118 */ "action_next_as_more_key",
- /* 119 */ "action_previous_as_more_key",
- /* 120 */ "label_to_more_symbol_key",
- /* 121 */ "label_to_more_symbol_for_tablet_key",
- /* 122 */ "label_tab_key",
- /* 123 */ "label_to_phone_numeric_key",
- /* 124 */ "label_to_phone_symbols_key",
- /* 125 */ "label_time_am",
- /* 126 */ "label_time_pm",
- /* 127 */ "label_to_symbol_key_pcqwerty",
- /* 128 */ "keylabel_for_popular_domain",
- /* 129 */ "more_keys_for_popular_domain",
- /* 130 */ "more_keys_for_smiley",
+ /* 43 */ "single_quotes",
+ /* 44 */ "double_quotes",
+ /* 45 */ "single_angle_quotes",
+ /* 46 */ "double_angle_quotes",
+ /* 47 */ "more_keys_for_currency_dollar",
+ /* 48 */ "keylabel_for_currency_generic",
+ /* 49 */ "more_keys_for_currency_generic",
+ /* 50 */ "more_keys_for_punctuation",
+ /* 51 */ "more_keys_for_star",
+ /* 52 */ "more_keys_for_bullet",
+ /* 53 */ "more_keys_for_plus",
+ /* 54 */ "more_keys_for_left_parenthesis",
+ /* 55 */ "more_keys_for_right_parenthesis",
+ /* 56 */ "more_keys_for_less_than",
+ /* 57 */ "more_keys_for_greater_than",
+ /* 58 */ "more_keys_for_arabic_diacritics",
+ /* 59 */ "keyhintlabel_for_arabic_diacritics",
+ /* 60 */ "keylabel_for_symbols_1",
+ /* 61 */ "keylabel_for_symbols_2",
+ /* 62 */ "keylabel_for_symbols_3",
+ /* 63 */ "keylabel_for_symbols_4",
+ /* 64 */ "keylabel_for_symbols_5",
+ /* 65 */ "keylabel_for_symbols_6",
+ /* 66 */ "keylabel_for_symbols_7",
+ /* 67 */ "keylabel_for_symbols_8",
+ /* 68 */ "keylabel_for_symbols_9",
+ /* 69 */ "keylabel_for_symbols_0",
+ /* 70 */ "label_to_symbol_key",
+ /* 71 */ "label_to_symbol_with_microphone_key",
+ /* 72 */ "additional_more_keys_for_symbols_1",
+ /* 73 */ "additional_more_keys_for_symbols_2",
+ /* 74 */ "additional_more_keys_for_symbols_3",
+ /* 75 */ "additional_more_keys_for_symbols_4",
+ /* 76 */ "additional_more_keys_for_symbols_5",
+ /* 77 */ "additional_more_keys_for_symbols_6",
+ /* 78 */ "additional_more_keys_for_symbols_7",
+ /* 79 */ "additional_more_keys_for_symbols_8",
+ /* 80 */ "additional_more_keys_for_symbols_9",
+ /* 81 */ "additional_more_keys_for_symbols_0",
+ /* 82 */ "more_keys_for_symbols_1",
+ /* 83 */ "more_keys_for_symbols_2",
+ /* 84 */ "more_keys_for_symbols_3",
+ /* 85 */ "more_keys_for_symbols_4",
+ /* 86 */ "more_keys_for_symbols_5",
+ /* 87 */ "more_keys_for_symbols_6",
+ /* 88 */ "more_keys_for_symbols_7",
+ /* 89 */ "more_keys_for_symbols_8",
+ /* 90 */ "more_keys_for_symbols_9",
+ /* 91 */ "more_keys_for_symbols_0",
+ /* 92 */ "keylabel_for_comma",
+ /* 93 */ "more_keys_for_comma",
+ /* 94 */ "keylabel_for_symbols_question",
+ /* 95 */ "keylabel_for_symbols_semicolon",
+ /* 96 */ "keylabel_for_symbols_percent",
+ /* 97 */ "more_keys_for_symbols_exclamation",
+ /* 98 */ "more_keys_for_symbols_question",
+ /* 99 */ "more_keys_for_symbols_semicolon",
+ /* 100 */ "more_keys_for_symbols_percent",
+ /* 101 */ "keylabel_for_tablet_comma",
+ /* 102 */ "keyhintlabel_for_tablet_comma",
+ /* 103 */ "more_keys_for_tablet_comma",
+ /* 104 */ "keyhintlabel_for_tablet_period",
+ /* 105 */ "more_keys_for_tablet_period",
+ /* 106 */ "keylabel_for_apostrophe",
+ /* 107 */ "keyhintlabel_for_apostrophe",
+ /* 108 */ "more_keys_for_apostrophe",
+ /* 109 */ "more_keys_for_q",
+ /* 110 */ "more_keys_for_x",
+ /* 111 */ "keylabel_for_q",
+ /* 112 */ "keylabel_for_w",
+ /* 113 */ "keylabel_for_y",
+ /* 114 */ "keylabel_for_x",
+ /* 115 */ "keylabel_for_spanish_row2_10",
+ /* 116 */ "more_keys_for_am_pm",
+ /* 117 */ "settings_as_more_key",
+ /* 118 */ "shortcut_as_more_key",
+ /* 119 */ "action_next_as_more_key",
+ /* 120 */ "action_previous_as_more_key",
+ /* 121 */ "label_to_more_symbol_key",
+ /* 122 */ "label_to_more_symbol_for_tablet_key",
+ /* 123 */ "label_tab_key",
+ /* 124 */ "label_to_phone_numeric_key",
+ /* 125 */ "label_to_phone_symbols_key",
+ /* 126 */ "label_time_am",
+ /* 127 */ "label_time_pm",
+ /* 128 */ "label_to_symbol_key_pcqwerty",
+ /* 129 */ "keylabel_for_popular_domain",
+ /* 130 */ "more_keys_for_popular_domain",
+ /* 131 */ "more_keys_for_smiley",
+ /* 132 */ "single_laqm_raqm",
+ /* 133 */ "single_laqm_raqm_rtl",
+ /* 134 */ "single_raqm_laqm",
+ /* 135 */ "double_laqm_raqm",
+ /* 136 */ "double_laqm_raqm_rtl",
+ /* 137 */ "double_raqm_laqm",
+ /* 138 */ "single_lqm_rqm",
+ /* 139 */ "single_9qm_lqm",
+ /* 140 */ "single_9qm_rqm",
+ /* 141 */ "double_lqm_rqm",
+ /* 142 */ "double_9qm_lqm",
+ /* 143 */ "double_9qm_rqm",
+ /* 144 */ "more_keys_for_single_quote",
+ /* 145 */ "more_keys_for_double_quote",
+ /* 146 */ "more_keys_for_tablet_double_quote",
};
private static final String EMPTY = "";
@@ -247,155 +263,182 @@ public final class KeyboardTextsSet {
/* ~41 */
// Label for "switch to alphabetic" key.
/* 42 */ "ABC",
- /* 43 */ "!fixedColumnOrder!4,\u2018,\u2019,\u201A,\u201B",
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB",
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+ /* 43 */ "!text/single_lqm_rqm",
+ /* 44 */ "!text/double_lqm_rqm",
+ /* 45 */ "!text/single_laqm_raqm",
+ /* 46 */ "!text/double_laqm_raqm",
// U+00A2: "¢" CENT SIGN
// U+00A3: "£" POUND SIGN
// U+20AC: "€" EURO SIGN
// U+00A5: "¥" YEN SIGN
// U+20B1: "₱" PESO SIGN
- /* 46 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
- /* 47 */ "$",
- /* 48 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
- /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
+ /* 47 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+ /* 48 */ "$",
+ /* 49 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
+ /* 50 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
// U+2020: "†" DAGGER
// U+2021: "‡" DOUBLE DAGGER
// U+2605: "★" BLACK STAR
- /* 50 */ "\u2020,\u2021,\u2605",
+ /* 51 */ "\u2020,\u2021,\u2605",
// U+266A: "♪" EIGHTH NOTE
// U+2665: "♥" BLACK HEART SUIT
// U+2660: "♠" BLACK SPADE SUIT
// U+2666: "♦" BLACK DIAMOND SUIT
// U+2663: "♣" BLACK CLUB SUIT
- /* 51 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
+ /* 52 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
// U+00B1: "±" PLUS-MINUS SIGN
- /* 52 */ "\u00B1",
+ /* 53 */ "\u00B1",
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
- /* 53 */ "!fixedColumnOrder!3,<,{,[",
- /* 54 */ "!fixedColumnOrder!3,>,},]",
+ /* 54 */ "!fixedColumnOrder!3,<,{,[",
+ /* 55 */ "!fixedColumnOrder!3,>,},]",
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- // The following characters don't need BIDI mirroring.
- // U+2018: "‘" LEFT SINGLE QUOTATION MARK
- // U+2019: "’" RIGHT SINGLE QUOTATION MARK
- // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- // U+201C: "“" LEFT DOUBLE QUOTATION MARK
- // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- /* 55 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
- /* 56 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
- /* 57 */ EMPTY,
+ /* 56 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
+ /* 57 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
/* 58 */ EMPTY,
- /* 59 */ "1",
- /* 60 */ "2",
- /* 61 */ "3",
- /* 62 */ "4",
- /* 63 */ "5",
- /* 64 */ "6",
- /* 65 */ "7",
- /* 66 */ "8",
- /* 67 */ "9",
- /* 68 */ "0",
+ /* 59 */ EMPTY,
+ /* 60 */ "1",
+ /* 61 */ "2",
+ /* 62 */ "3",
+ /* 63 */ "4",
+ /* 64 */ "5",
+ /* 65 */ "6",
+ /* 66 */ "7",
+ /* 67 */ "8",
+ /* 68 */ "9",
+ /* 69 */ "0",
// Label for "switch to symbols" key.
- /* 69 */ "?123",
+ /* 70 */ "?123",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 70 */ "123",
- /* 71~ */
+ /* 71 */ "123",
+ /* 72~ */
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
- /* ~80 */
+ /* ~81 */
// U+00B9: "¹" SUPERSCRIPT ONE
// U+00BD: "½" VULGAR FRACTION ONE HALF
// U+2153: "⅓" VULGAR FRACTION ONE THIRD
// U+00BC: "¼" VULGAR FRACTION ONE QUARTER
// U+215B: "⅛" VULGAR FRACTION ONE EIGHTH
- /* 81 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+ /* 82 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
// U+00B2: "²" SUPERSCRIPT TWO
// U+2154: "⅔" VULGAR FRACTION TWO THIRDS
- /* 82 */ "\u00B2,\u2154",
+ /* 83 */ "\u00B2,\u2154",
// U+00B3: "³" SUPERSCRIPT THREE
// U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
// U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
- /* 83 */ "\u00B3,\u00BE,\u215C",
+ /* 84 */ "\u00B3,\u00BE,\u215C",
// U+2074: "⁴" SUPERSCRIPT FOUR
- /* 84 */ "\u2074",
+ /* 85 */ "\u2074",
// U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
- /* 85 */ "\u215D",
- /* 86 */ EMPTY,
+ /* 86 */ "\u215D",
+ /* 87 */ EMPTY,
// U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
- /* 87 */ "\u215E",
- /* 88 */ EMPTY,
+ /* 88 */ "\u215E",
/* 89 */ EMPTY,
+ /* 90 */ EMPTY,
// U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
// U+2205: "∅" EMPTY SET
- /* 90 */ "\u207F,\u2205",
- /* 91 */ ",",
- /* 92 */ EMPTY,
- /* 93 */ "?",
- /* 94 */ ";",
- /* 95 */ "%",
+ /* 91 */ "\u207F,\u2205",
+ /* 92 */ ",",
+ /* 93 */ EMPTY,
+ /* 94 */ "?",
+ /* 95 */ ";",
+ /* 96 */ "%",
// U+00A1: "¡" INVERTED EXCLAMATION MARK
- /* 96 */ "\u00A1",
+ /* 97 */ "\u00A1",
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 97 */ "\u00BF",
- /* 98 */ EMPTY,
+ /* 98 */ "\u00BF",
+ /* 99 */ EMPTY,
// U+2030: "‰" PER MILLE SIGN
- /* 99 */ "\u2030",
- /* 100 */ ",",
- /* 101 */ "!",
+ /* 100 */ "\u2030",
+ /* 101 */ ",",
/* 102 */ "!",
- /* 103 */ "?",
+ /* 103 */ "!",
/* 104 */ "?",
- /* 105 */ "\'",
- /* 106 */ "\"",
+ /* 105 */ "?",
+ /* 106 */ "\'",
/* 107 */ "\"",
- /* 108 */ EMPTY,
+ /* 108 */ "\"",
/* 109 */ EMPTY,
- /* 110 */ "q",
- /* 111 */ "w",
- /* 112 */ "y",
- /* 113 */ "x",
+ /* 110 */ EMPTY,
+ /* 111 */ "q",
+ /* 112 */ "w",
+ /* 113 */ "y",
+ /* 114 */ "x",
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
- /* 114 */ "\u00F1",
- /* 115 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
- /* 116 */ "!icon/settings_key|!code/key_settings",
- /* 117 */ "!icon/shortcut_key|!code/key_shortcut",
- /* 118 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
- /* 119 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
+ /* 115 */ "\u00F1",
+ /* 116 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
+ /* 117 */ "!icon/settings_key|!code/key_settings",
+ /* 118 */ "!icon/shortcut_key|!code/key_shortcut",
+ /* 119 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
+ /* 120 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
// Label for "switch to more symbol" modifier key. Must be short to fit on key!
- /* 120 */ "= \\ <",
+ /* 121 */ "= \\ <",
// Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key!
- /* 121 */ "~ \\ {",
+ /* 122 */ "~ \\ {",
// Label for "Tab" key. Must be short to fit on key!
- /* 122 */ "Tab",
+ /* 123 */ "Tab",
// Label for "switch to phone numeric" key. Must be short to fit on key!
- /* 123 */ "123",
+ /* 124 */ "123",
// Label for "switch to phone symbols" key. Must be short to fit on key!
// U+FF0A: "*" FULLWIDTH ASTERISK
// U+FF03: "#" FULLWIDTH NUMBER SIGN
- /* 124 */ "\uFF0A\uFF03",
+ /* 125 */ "\uFF0A\uFF03",
// Key label for "ante meridiem"
- /* 125 */ "AM",
+ /* 126 */ "AM",
// Key label for "post meridiem"
- /* 126 */ "PM",
+ /* 127 */ "PM",
// Label for "switch to symbols" key on PC QWERTY layout
- /* 127 */ "Sym",
- /* 128 */ ".com",
+ /* 128 */ "Sym",
+ /* 129 */ ".com",
// popular web domains for the locale - most popular, displayed on the keyboard
- /* 129 */ "!hasLabels!,.net,.org,.gov,.edu",
- /* 130 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
+ /* 130 */ "!hasLabels!,.net,.org,.gov,.edu",
+ /* 131 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
+ // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ // The following characters don't need BIDI mirroring.
+ // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+ // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+ // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+ // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+ // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+ // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+ // Abbreviations are:
+ // laqm: LEFT-POINTING ANGLE QUOTATION MARK
+ // raqm: RIGHT-POINTING ANGLE QUOTATION MARK
+ // rtl: Right-To-Left script order
+ // lqm: LEFT QUOTATION MARK
+ // rqm: RIGHT QUOTATION MARK
+ // 9qm: LOW-9 QUOTATION MARK
+ // The following each quotation mark pair consist of
+ // <opening quotation mark>, <closing quotation mark>
+ // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>.
+ /* 132 */ "\u2039,\u203A",
+ /* 133 */ "\u2039|\u203A,\u203A|\u2039",
+ /* 134 */ "\u203A,\u2039",
+ /* 135 */ "\u00AB,\u00BB",
+ /* 136 */ "\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 137 */ "\u00BB,\u00AB",
+ // The following each quotation mark triplet consists of
+ // <another quotation mark>, <opening quotation mark>, <closing quotation mark>
+ // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>.
+ /* 138 */ "\u201A,\u2018,\u2019",
+ /* 139 */ "\u2019,\u201A,\u2018",
+ /* 140 */ "\u2018,\u201A,\u2019",
+ /* 141 */ "\u201E,\u201C,\u201D",
+ /* 142 */ "\u201D,\u201E,\u201C",
+ /* 143 */ "\u201C,\u201E,\u201D",
+ /* 144 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
+ /* 145 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
+ /* 146 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
};
/* Language af: Afrikaans */
@@ -465,54 +508,36 @@ public final class KeyboardTextsSet {
// U+062C: "پ" ARABIC LETTER PEH
/* 42 */ "\u0623\u200C\u0628\u200C\u062C",
/* 43 */ null,
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
- // U+00A2: "¢" CENT SIGN
- // U+00A3: "£" POUND SIGN
- // U+20AC: "€" EURO SIGN
- // U+00A5: "¥" YEN SIGN
- // U+20B1: "₱" PESO SIGN
- // U+FDFC: "﷼" RIAL SIGN
- /* 46 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1,\uFDFC",
- /* 47 */ null,
- /* 48 */ null,
+ /* 44 */ null,
+ /* 45 */ "!text/single_laqm_raqm_rtl",
+ /* 46 */ "!text/double_laqm_raqm_rtl",
+ /* 47~ */
+ null, null, null,
+ /* ~49 */
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
- /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
+ /* 50 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
// U+2605: "★" BLACK STAR
// U+066D: "٭" ARABIC FIVE POINTED STAR
- /* 50 */ "\u2605,\u066D",
+ /* 51 */ "\u2605,\u066D",
// U+266A: "♪" EIGHTH NOTE
- /* 51 */ "\u266A",
- /* 52 */ null,
+ /* 52 */ "\u266A",
+ /* 53 */ null,
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
// U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
// U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS
- /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
- /* 54 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+ /* 54 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+ /* 55 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- // The following characters don't need BIDI mirroring.
- // U+2018: "‘" LEFT SINGLE QUOTATION MARK
- // U+2019: "’" RIGHT SINGLE QUOTATION MARK
- // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- // U+201C: "“" LEFT DOUBLE QUOTATION MARK
- // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
- /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+ /* 56 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+ /* 57 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
// U+0655: "ٕ" ARABIC HAMZA BELOW
// U+0654: "ٔ" ARABIC HAMZA ABOVE
// U+0652: "ْ" ARABIC SUKUN
@@ -529,70 +554,70 @@ public final class KeyboardTextsSet {
// U+0640: "ـ" ARABIC TATWEEL
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
// Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly.
- /* 57 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
- /* 58 */ "\u0651",
+ /* 58 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
+ /* 59 */ "\u0651",
// U+0661: "١" ARABIC-INDIC DIGIT ONE
- /* 59 */ "\u0661",
+ /* 60 */ "\u0661",
// U+0662: "٢" ARABIC-INDIC DIGIT TWO
- /* 60 */ "\u0662",
+ /* 61 */ "\u0662",
// U+0663: "٣" ARABIC-INDIC DIGIT THREE
- /* 61 */ "\u0663",
+ /* 62 */ "\u0663",
// U+0664: "٤" ARABIC-INDIC DIGIT FOUR
- /* 62 */ "\u0664",
+ /* 63 */ "\u0664",
// U+0665: "٥" ARABIC-INDIC DIGIT FIVE
- /* 63 */ "\u0665",
+ /* 64 */ "\u0665",
// U+0666: "٦" ARABIC-INDIC DIGIT SIX
- /* 64 */ "\u0666",
+ /* 65 */ "\u0666",
// U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
- /* 65 */ "\u0667",
+ /* 66 */ "\u0667",
// U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
- /* 66 */ "\u0668",
+ /* 67 */ "\u0668",
// U+0669: "٩" ARABIC-INDIC DIGIT NINE
- /* 67 */ "\u0669",
+ /* 68 */ "\u0669",
// U+0660: "٠" ARABIC-INDIC DIGIT ZERO
- /* 68 */ "\u0660",
+ /* 69 */ "\u0660",
// Label for "switch to symbols" key.
// U+061F: "؟" ARABIC QUESTION MARK
- /* 69 */ "\u0663\u0662\u0661\u061F",
+ /* 70 */ "\u0663\u0662\u0661\u061F",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 70 */ "\u0663\u0662\u0661",
- /* 71 */ "1",
- /* 72 */ "2",
- /* 73 */ "3",
- /* 74 */ "4",
- /* 75 */ "5",
- /* 76 */ "6",
- /* 77 */ "7",
- /* 78 */ "8",
- /* 79 */ "9",
+ /* 71 */ "\u0663\u0662\u0661",
+ /* 72 */ "1",
+ /* 73 */ "2",
+ /* 74 */ "3",
+ /* 75 */ "4",
+ /* 76 */ "5",
+ /* 77 */ "6",
+ /* 78 */ "7",
+ /* 79 */ "8",
+ /* 80 */ "9",
// U+066B: "٫" ARABIC DECIMAL SEPARATOR
// U+066C: "٬" ARABIC THOUSANDS SEPARATOR
- /* 80 */ "0,\u066B,\u066C",
- /* 81~ */
+ /* 81 */ "0,\u066B,\u066C",
+ /* 82~ */
null, null, null, null, null, null, null, null, null, null,
- /* ~90 */
+ /* ~91 */
// U+060C: "،" ARABIC COMMA
- /* 91 */ "\u060C",
- /* 92 */ "\\,",
- /* 93 */ "\u061F",
- /* 94 */ "\u061B",
+ /* 92 */ "\u060C",
+ /* 93 */ "\\,",
+ /* 94 */ "\u061F",
+ /* 95 */ "\u061B",
// U+066A: "٪" ARABIC PERCENT SIGN
- /* 95 */ "\u066A",
- /* 96 */ null,
- /* 97 */ "?",
- /* 98 */ ";",
+ /* 96 */ "\u066A",
+ /* 97 */ null,
+ /* 98 */ "?",
+ /* 99 */ ";",
// U+2030: "‰" PER MILLE SIGN
- /* 99 */ "\\%,\u2030",
- /* 100~ */
+ /* 100 */ "\\%,\u2030",
+ /* 101~ */
null, null, null, null, null,
- /* ~104 */
+ /* ~105 */
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
// U+061F: "؟" ARABIC QUESTION MARK
- /* 105 */ "\u060C",
- /* 106 */ "\u061F",
- /* 107 */ "\u061F,\u061B,!,:,-,/,\',\"",
+ /* 106 */ "\u060C",
+ /* 107 */ "\u061F",
+ /* 108 */ "\u061F,\u061B,!,:,-,/,\',\"",
};
/* Language be: Belarusian */
@@ -627,6 +652,8 @@ public final class KeyboardTextsSet {
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* 42 */ "\u0410\u0411\u0412",
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language bg: Bulgarian */
@@ -641,6 +668,9 @@ public final class KeyboardTextsSet {
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* 42 */ "\u0410\u0411\u0412",
+ /* 43 */ null,
+ // single_quotes of Bulgarian is default single_quotes_right_left.
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language ca: Catalan */
@@ -771,6 +801,14 @@ public final class KeyboardTextsSet {
// U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
// U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
/* 12 */ "\u017E,\u017A,\u017C",
+ /* 13~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language da: Danish */
@@ -832,6 +870,14 @@ public final class KeyboardTextsSet {
/* 23 */ "\u00E4",
// U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
/* 24 */ "\u00F6",
+ /* 25~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language de: German */
@@ -874,6 +920,15 @@ public final class KeyboardTextsSet {
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
// U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
/* 6 */ "\u00F1,\u0144",
+ /* 7~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language el: Greek */
@@ -1058,20 +1113,20 @@ public final class KeyboardTextsSet {
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null,
- /* ~107 */
- /* 108 */ "q",
- /* 109 */ "x",
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~108 */
+ /* 109 */ "q",
+ /* 110 */ "x",
// U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX
- /* 110 */ "\u015D",
+ /* 111 */ "\u015D",
// U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX
- /* 111 */ "\u011D",
+ /* 112 */ "\u011D",
// U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE
- /* 112 */ "\u016D",
+ /* 113 */ "\u016D",
// U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX
- /* 113 */ "\u0109",
+ /* 114 */ "\u0109",
// U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX
- /* 114 */ "\u0135",
+ /* 115 */ "\u0135",
};
/* Language es: Spanish */
@@ -1129,25 +1184,25 @@ public final class KeyboardTextsSet {
/* 8~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- /* ~48 */
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~49 */
// U+00A1: "¡" INVERTED EXCLAMATION MARK
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 49 */ "!fixedColumnOrder!9,\u00A1,\",\',#,-,:,!,\\,,?,\u00BF,@,&,\\%,+,;,/,(,)",
- /* 50~ */
+ /* 50 */ "!fixedColumnOrder!9,\u00A1,\",\',#,-,:,!,\\,,?,\u00BF,@,&,\\%,+,;,/,(,)",
+ /* 51~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
- /* ~101 */
+ /* ~102 */
// U+00A1: "¡" INVERTED EXCLAMATION MARK
- /* 102 */ "!,\u00A1",
- /* 103 */ null,
+ /* 103 */ "!,\u00A1",
+ /* 104 */ null,
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 104 */ "?,\u00BF",
- /* 105 */ "\"",
- /* 106 */ "\'",
+ /* 105 */ "?,\u00BF",
+ /* 106 */ "\"",
/* 107 */ "\'",
+ /* 108 */ "\'",
};
/* Language et: Estonian */
@@ -1248,6 +1303,12 @@ public final class KeyboardTextsSet {
/* 22 */ "\u00E4",
// U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
/* 23 */ "\u00F5",
+ /* 24~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language fa: Persian */
@@ -1264,55 +1325,36 @@ public final class KeyboardTextsSet {
// U+067E: "پ" ARABIC LETTER PEH
/* 42 */ "\u0627\u200C\u0628\u200C\u067E",
/* 43 */ null,
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\",\'",
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
- /* 46 */ null,
- // U+FDFC: "﷼" RIAL SIGN
- // U+060B: "؋" AFGHANI SIGN
- // U+00A2: "¢" CENT SIGN
- // U+00A3: "£" POUND SIGN
- // U+20AC: "€" EURO SIGN
- // U+00A5: "¥" YEN SIGN
- // U+20B1: "₱" PESO SIGN
- /* 47 */ "\uFDFC",
- /* 48 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1,\u060B",
+ /* 44 */ null,
+ /* 45 */ "!text/single_laqm_raqm_rtl",
+ /* 46 */ "!text/double_laqm_raqm_rtl",
+ /* 47~ */
+ null, null, null,
+ /* ~49 */
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
- /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
+ /* 50 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
// U+2605: "★" BLACK STAR
// U+066D: "٭" ARABIC FIVE POINTED STAR
- /* 50 */ "\u2605,\u066D",
+ /* 51 */ "\u2605,\u066D",
// U+266A: "♪" EIGHTH NOTE
- /* 51 */ "\u266A",
- /* 52 */ null,
+ /* 52 */ "\u266A",
+ /* 53 */ null,
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
// U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
// U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS
- /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
- /* 54 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+ /* 54 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+ /* 55 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- // The following characters don't need BIDI mirroring.
- // U+2018: "‘" LEFT SINGLE QUOTATION MARK
- // U+2019: "’" RIGHT SINGLE QUOTATION MARK
- // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- // U+201C: "“" LEFT DOUBLE QUOTATION MARK
- // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>",
- /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<",
+ /* 56 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>",
+ /* 57 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<",
// U+0655: "ٕ" ARABIC HAMZA BELOW
// U+0652: "ْ" ARABIC SUKUN
// U+0651: "ّ" ARABIC SHADDA
@@ -1329,74 +1371,74 @@ public final class KeyboardTextsSet {
// U+0640: "ـ" ARABIC TATWEEL
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
// Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly.
- /* 57 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
- /* 58 */ "\u064B",
+ /* 58 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
+ /* 59 */ "\u064B",
// U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
- /* 59 */ "\u06F1",
+ /* 60 */ "\u06F1",
// U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
- /* 60 */ "\u06F2",
+ /* 61 */ "\u06F2",
// U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE
- /* 61 */ "\u06F3",
+ /* 62 */ "\u06F3",
// U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR
- /* 62 */ "\u06F4",
+ /* 63 */ "\u06F4",
// U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE
- /* 63 */ "\u06F5",
+ /* 64 */ "\u06F5",
// U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX
- /* 64 */ "\u06F6",
+ /* 65 */ "\u06F6",
// U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN
- /* 65 */ "\u06F7",
+ /* 66 */ "\u06F7",
// U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT
- /* 66 */ "\u06F8",
+ /* 67 */ "\u06F8",
// U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE
- /* 67 */ "\u06F9",
+ /* 68 */ "\u06F9",
// U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
- /* 68 */ "\u06F0",
+ /* 69 */ "\u06F0",
// Label for "switch to symbols" key.
// U+061F: "؟" ARABIC QUESTION MARK
- /* 69 */ "\u06F3\u06F2\u06F1\u061F",
+ /* 70 */ "\u06F3\u06F2\u06F1\u061F",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 70 */ "\u06F3\u06F2\u06F1",
- /* 71 */ "1",
- /* 72 */ "2",
- /* 73 */ "3",
- /* 74 */ "4",
- /* 75 */ "5",
- /* 76 */ "6",
- /* 77 */ "7",
- /* 78 */ "8",
- /* 79 */ "9",
+ /* 71 */ "\u06F3\u06F2\u06F1",
+ /* 72 */ "1",
+ /* 73 */ "2",
+ /* 74 */ "3",
+ /* 75 */ "4",
+ /* 76 */ "5",
+ /* 77 */ "6",
+ /* 78 */ "7",
+ /* 79 */ "8",
+ /* 80 */ "9",
// U+066B: "٫" ARABIC DECIMAL SEPARATOR
// U+066C: "٬" ARABIC THOUSANDS SEPARATOR
- /* 80 */ "0,\u066B,\u066C",
- /* 81~ */
+ /* 81 */ "0,\u066B,\u066C",
+ /* 82~ */
null, null, null, null, null, null, null, null, null, null,
- /* ~90 */
+ /* ~91 */
// U+060C: "،" ARABIC COMMA
- /* 91 */ "\u060C",
- /* 92 */ "\\,",
- /* 93 */ "\u061F",
- /* 94 */ "\u061B",
+ /* 92 */ "\u060C",
+ /* 93 */ "\\,",
+ /* 94 */ "\u061F",
+ /* 95 */ "\u061B",
// U+066A: "٪" ARABIC PERCENT SIGN
- /* 95 */ "\u066A",
- /* 96 */ null,
- /* 97 */ "?",
- /* 98 */ ";",
+ /* 96 */ "\u066A",
+ /* 97 */ null,
+ /* 98 */ "?",
+ /* 99 */ ";",
// U+2030: "‰" PER MILLE SIGN
- /* 99 */ "\\%,\u2030",
+ /* 100 */ "\\%,\u2030",
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
// U+061F: "؟" ARABIC QUESTION MARK
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- /* 100 */ "\u060C",
- /* 101 */ "!",
- /* 102 */ "!,\\,",
- /* 103 */ "\u061F",
- /* 104 */ "\u061F,?",
- /* 105 */ "\u060C",
- /* 106 */ "\u061F",
- /* 107 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 101 */ "\u060C",
+ /* 102 */ "!",
+ /* 103 */ "!,\\,",
+ /* 104 */ "\u061F",
+ /* 105 */ "\u061F,?",
+ /* 106 */ "\u060C",
+ /* 107 */ "\u061F",
+ /* 108 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
};
/* Language fi: Finnish */
@@ -1512,48 +1554,48 @@ public final class KeyboardTextsSet {
// U+0917: "ग" DEVANAGARI LETTER GA
/* 42 */ "\u0915\u0916\u0917",
/* 43~ */
- null, null, null, null,
- /* ~46 */
+ null, null, null, null, null,
+ /* ~47 */
// U+20B9: "₹" INDIAN RUPEE SIGN
- /* 47 */ "\u20B9",
- /* 48~ */
+ /* 48 */ "\u20B9",
+ /* 49~ */
null, null, null, null, null, null, null, null, null, null, null,
- /* ~58 */
+ /* ~59 */
// U+0967: "१" DEVANAGARI DIGIT ONE
- /* 59 */ "\u0967",
+ /* 60 */ "\u0967",
// U+0968: "२" DEVANAGARI DIGIT TWO
- /* 60 */ "\u0968",
+ /* 61 */ "\u0968",
// U+0969: "३" DEVANAGARI DIGIT THREE
- /* 61 */ "\u0969",
+ /* 62 */ "\u0969",
// U+096A: "४" DEVANAGARI DIGIT FOUR
- /* 62 */ "\u096A",
+ /* 63 */ "\u096A",
// U+096B: "५" DEVANAGARI DIGIT FIVE
- /* 63 */ "\u096B",
+ /* 64 */ "\u096B",
// U+096C: "६" DEVANAGARI DIGIT SIX
- /* 64 */ "\u096C",
+ /* 65 */ "\u096C",
// U+096D: "७" DEVANAGARI DIGIT SEVEN
- /* 65 */ "\u096D",
+ /* 66 */ "\u096D",
// U+096E: "८" DEVANAGARI DIGIT EIGHT
- /* 66 */ "\u096E",
+ /* 67 */ "\u096E",
// U+096F: "९" DEVANAGARI DIGIT NINE
- /* 67 */ "\u096F",
+ /* 68 */ "\u096F",
// U+0966: "०" DEVANAGARI DIGIT ZERO
- /* 68 */ "\u0966",
+ /* 69 */ "\u0966",
// Label for "switch to symbols" key.
- /* 69 */ "?\u0967\u0968\u0969",
+ /* 70 */ "?\u0967\u0968\u0969",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 70 */ "\u0967\u0968\u0969",
- /* 71 */ "1",
- /* 72 */ "2",
- /* 73 */ "3",
- /* 74 */ "4",
- /* 75 */ "5",
- /* 76 */ "6",
- /* 77 */ "7",
- /* 78 */ "8",
- /* 79 */ "9",
- /* 80 */ "0",
+ /* 71 */ "\u0967\u0968\u0969",
+ /* 72 */ "1",
+ /* 73 */ "2",
+ /* 74 */ "3",
+ /* 75 */ "4",
+ /* 76 */ "5",
+ /* 77 */ "6",
+ /* 78 */ "7",
+ /* 79 */ "8",
+ /* 80 */ "9",
+ /* 81 */ "0",
};
/* Language hr: Croatian */
@@ -1581,6 +1623,14 @@ public final class KeyboardTextsSet {
// U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
// U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
/* 12 */ "\u017E,\u017A,\u017C",
+ /* 13~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_rqm",
+ /* 44 */ "!text/double_9qm_rqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language hu: Hungarian */
@@ -1626,6 +1676,15 @@ public final class KeyboardTextsSet {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* 4 */ "\u00FA,\u00FC,\u0171,\u00FB,\u00F9,\u016B",
+ /* 5~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_rqm",
+ /* 44 */ "!text/double_9qm_rqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language is: Icelandic */
@@ -1689,6 +1748,12 @@ public final class KeyboardTextsSet {
/* 21 */ "\u00E6",
// U+00FE: "þ" LATIN SMALL LETTER THORN
/* 22 */ "\u00FE",
+ /* 23~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language it: Italian */
@@ -1748,45 +1813,38 @@ public final class KeyboardTextsSet {
// U+05D1: "ב" HEBREW LETTER BET
// U+05D2: "ג" HEBREW LETTER GIMEL
/* 42 */ "\u05D0\u05D1\u05D2",
- /* 43 */ null,
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
- /* 44 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 45 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
- /* 46 */ null,
- // U+20AA: "₪" NEW SHEQEL SIGN
- /* 47 */ "\u20AA",
- /* 48 */ null,
- /* 49 */ null,
+ // The following characters don't need BIDI mirroring.
+ // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+ // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+ // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+ // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+ // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+ // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+ /* 43 */ "\u2018,\u2019,\u201A",
+ /* 44 */ "\u201C,\u201D,\u201E",
+ /* 45 */ "!text/single_laqm_raqm_rtl",
+ /* 46 */ "!text/double_laqm_raqm_rtl",
+ /* 47~ */
+ null, null, null, null,
+ /* ~50 */
// U+2605: "★" BLACK STAR
- /* 50 */ "\u2605",
- /* 51 */ null,
+ /* 51 */ "\u2605",
+ /* 52 */ null,
// U+00B1: "±" PLUS-MINUS SIGN
// U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN
- /* 52 */ "\u00B1,\uFB29",
+ /* 53 */ "\u00B1,\uFB29",
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
- /* 53 */ "!fixedColumnOrder!3,<|>,{|},[|]",
- /* 54 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
+ /* 54 */ "!fixedColumnOrder!3,<|>,{|},[|]",
+ /* 55 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- // The following characters don't need BIDI mirroring.
- // U+2018: "‘" LEFT SINGLE QUOTATION MARK
- // U+2019: "’" RIGHT SINGLE QUOTATION MARK
- // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- // U+201C: "“" LEFT DOUBLE QUOTATION MARK
- // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
- /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+ /* 56 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+ /* 57 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
};
/* Language ka: Georgian */
@@ -1801,6 +1859,8 @@ public final class KeyboardTextsSet {
// U+10D1: "ბ" GEORGIAN LETTER BAN
// U+10D2: "გ" GEORGIAN LETTER GAN
/* 42 */ "\u10D0\u10D1\u10D2",
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language ky: Kirghiz */
@@ -1930,6 +1990,12 @@ public final class KeyboardTextsSet {
// U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
// U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
/* 15 */ "\u0123,\u011F",
+ /* 16~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language lv: Latvian */
@@ -2019,6 +2085,12 @@ public final class KeyboardTextsSet {
// U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
// U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
/* 15 */ "\u0123,\u011F",
+ /* 16~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language mk: Macedonian */
@@ -2045,21 +2117,8 @@ public final class KeyboardTextsSet {
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* 42 */ "\u0410\u0411\u0412",
- /* 43 */ null,
- // U+2018: "‘" LEFT SINGLE QUOTATION MARK
- // U+2019: "’" RIGHT SINGLE QUOTATION MARK
- // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- // U+201C: "“" LEFT DOUBLE QUOTATION MARK
- // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201E;,&#x201C;,&#x201D;,&#x201F;,&#x00AB;,&#x00BB;</string>
- /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 45 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language mn: Mongolian */
@@ -2075,10 +2134,10 @@ public final class KeyboardTextsSet {
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* 42 */ "\u0410\u0411\u0412",
/* 43~ */
- null, null, null, null,
- /* ~46 */
+ null, null, null, null, null,
+ /* ~47 */
// U+20AE: "₮" TUGRIK SIGN
- /* 47 */ "\u20AE",
+ /* 48 */ "\u20AE",
};
/* Language nb: Norwegian Bokmål */
@@ -2126,6 +2185,12 @@ public final class KeyboardTextsSet {
/* 23 */ "\u00F6",
// U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
/* 24 */ "\u00E4",
+ /* 25~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_rqm",
+ /* 44 */ "!text/double_9qm_rqm",
};
/* Language nl: Dutch */
@@ -2177,6 +2242,13 @@ public final class KeyboardTextsSet {
/* 7 */ null,
// U+0133: "ij" LATIN SMALL LIGATURE IJ
/* 8 */ "\u0133",
+ /* 9~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_rqm",
+ /* 44 */ "!text/double_9qm_rqm",
};
/* Language pl: Polish */
@@ -2231,6 +2303,12 @@ public final class KeyboardTextsSet {
/* 13 */ null,
// U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
/* 14 */ "\u0142",
+ /* 15~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_rqm",
+ /* 44 */ "!text/double_9qm_rqm",
};
/* Language pt: Portuguese */
@@ -2330,6 +2408,13 @@ public final class KeyboardTextsSet {
/* ~10 */
// U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW
/* 11 */ "\u021B",
+ /* 12~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_rqm",
+ /* 44 */ "!text/double_9qm_rqm",
};
/* Language ru: Russian */
@@ -2364,6 +2449,8 @@ public final class KeyboardTextsSet {
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* 42 */ "\u0410\u0411\u0412",
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
};
/* Language sk: Slovak */
@@ -2454,6 +2541,14 @@ public final class KeyboardTextsSet {
// U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
// U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
/* 15 */ "\u0123,\u011F",
+ /* 16~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language sl: Slovenian */
@@ -2474,6 +2569,14 @@ public final class KeyboardTextsSet {
/* 11 */ null,
// U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
/* 12 */ "\u017E",
+ /* 13~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~42 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language sr: Serbian */
@@ -2519,21 +2622,10 @@ public final class KeyboardTextsSet {
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* 42 */ "\u0410\u0411\u0412",
- /* 43 */ null,
- // U+2018: "‘" LEFT SINGLE QUOTATION MARK
- // U+2019: "’" RIGHT SINGLE QUOTATION MARK
- // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
- // U+201C: "“" LEFT DOUBLE QUOTATION MARK
- // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
- // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201E;,&#x201C;,&#x201D;,&#x201F;,&#x00AB;,&#x00BB;</string>
- /* 44 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
- // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.
- // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
- /* 45 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language sv: Swedish */
@@ -2576,6 +2668,12 @@ public final class KeyboardTextsSet {
/* 23 */ "\u00F8",
// U+00E6: "æ" LATIN SMALL LETTER AE
/* 24 */ "\u00E6",
+ /* 25~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null,
+ /* ~44 */
+ /* 45 */ "!text/single_raqm_laqm",
+ /* 46 */ "!text/double_raqm_laqm",
};
/* Language sw: Swahili */
@@ -2642,10 +2740,10 @@ public final class KeyboardTextsSet {
// U+0E04: "ค" THAI CHARACTER KHO KHWAI
/* 42 */ "\u0E01\u0E02\u0E04",
/* 43~ */
- null, null, null, null,
- /* ~46 */
+ null, null, null, null, null,
+ /* ~47 */
// U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT
- /* 47 */ "\u0E3F",
+ /* 48 */ "\u0E3F",
};
/* Language tl: Tagalog */
@@ -2780,11 +2878,13 @@ public final class KeyboardTextsSet {
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* 42 */ "\u0410\u0411\u0412",
- /* 43~ */
- null, null, null, null,
- /* ~46 */
+ /* 43 */ "!text/single_9qm_lqm",
+ /* 44 */ "!text/double_9qm_lqm",
+ /* 45~ */
+ null, null, null,
+ /* ~47 */
// U+20B4: "₴" HRYVNIA SIGN
- /* 47 */ "\u20B4",
+ /* 48 */ "\u20B4",
};
/* Language vi: Vietnamese */
@@ -2869,10 +2969,10 @@ public final class KeyboardTextsSet {
/* 10~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null,
- /* ~46 */
+ null, null, null, null, null, null, null, null,
+ /* ~47 */
// U+20AB: "₫" DONG SIGN
- /* 47 */ "\u20AB",
+ /* 48 */ "\u20AB",
};
/* Language zu: Zulu */
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index ad3163347..ab2a12fd0 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -16,7 +16,6 @@
package com.android.inputmethod.latin;
-import android.content.Context;
import android.text.TextUtils;
import android.util.SparseArray;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index d9d664fb5..0d0ce5756 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -74,6 +74,8 @@ public final class BinaryDictionaryFileDumper {
// The path fragment to append after the client ID for dictionary info requests.
private static final String QUERY_PATH_DICT_INFO = "dict";
+ // The path fragment to append after the client ID for dictionary datafile requests.
+ private static final String QUERY_PATH_DATAFILE = "datafile";
// The path fragment to append after the client ID for updating the metadata URI.
private static final String QUERY_PATH_METADATA = "metadata";
private static final String INSERT_METADATA_CLIENT_ID_COLUMN = "clientid";
@@ -156,7 +158,7 @@ public final class BinaryDictionaryFileDumper {
c.close();
return Collections.<WordListInfo>emptyList();
}
- final List<WordListInfo> list = CollectionUtils.newArrayList();
+ final ArrayList<WordListInfo> list = CollectionUtils.newArrayList();
do {
final String wordListId = c.getString(0);
final String wordListLocale = c.getString(1);
@@ -186,13 +188,18 @@ public final class BinaryDictionaryFileDumper {
/**
* Helper method to encapsulate exception handling.
*/
- private static AssetFileDescriptor openAssetFileDescriptor(final ContentResolver resolver,
- final Uri uri) {
+ private static AssetFileDescriptor openAssetFileDescriptor(
+ final ContentProviderClient providerClient, final Uri uri) {
try {
- return resolver.openAssetFileDescriptor(uri, "r");
+ return providerClient.openAssetFile(uri, "r");
} catch (FileNotFoundException e) {
- // I don't want to log the word list URI here for security concerns
- Log.e(TAG, "Could not find a word list from the dictionary provider.");
+ // I don't want to log the word list URI here for security concerns. The exception
+ // contains the name of the file, so let's not pass it to Log.e here.
+ Log.e(TAG, "Could not find a word list from the dictionary provider."
+ /* intentionally don't pass the exception (see comment above) */);
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't communicate with the dictionary pack", e);
return null;
}
}
@@ -202,9 +209,8 @@ public final class BinaryDictionaryFileDumper {
* to the cache file name designated by its id and locale, overwriting it if already present
* and creating it (and its containing directory) if necessary.
*/
- private static AssetFileAddress cacheWordList(final String id, final String locale,
- final ContentResolver resolver, final Context context) {
-
+ private static AssetFileAddress cacheWordList(final String wordlistId, final String locale,
+ final ContentProviderClient providerClient, final Context context) {
final int COMPRESSED_CRYPTED_COMPRESSED = 0;
final int CRYPTED_COMPRESSED = 1;
final int COMPRESSED_CRYPTED = 2;
@@ -214,11 +220,20 @@ public final class BinaryDictionaryFileDumper {
final int MODE_MIN = COMPRESSED_CRYPTED_COMPRESSED;
final int MODE_MAX = NONE;
- final Uri.Builder wordListUriBuilder = getProviderUriBuilder(id);
- final String finalFileName = DictionaryInfoUtils.getCacheFileName(id, locale, context);
+ final String clientId = context.getString(R.string.dictionary_pack_client_id);
+ final Uri.Builder wordListUriBuilder;
+ try {
+ wordListUriBuilder = getContentUriBuilderForType(clientId,
+ providerClient, QUERY_PATH_DATAFILE, wordlistId /* extraPath */);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't communicate with the dictionary pack", e);
+ return null;
+ }
+ final String finalFileName =
+ DictionaryInfoUtils.getCacheFileName(wordlistId, locale, context);
String tempFileName;
try {
- tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
+ tempFileName = BinaryDictionaryGetter.getTempFileName(wordlistId, context);
} catch (IOException e) {
Log.e(TAG, "Can't open the temporary file", e);
return null;
@@ -236,7 +251,7 @@ public final class BinaryDictionaryFileDumper {
final Uri wordListUri = wordListUriBuilder.build();
try {
// Open input.
- afd = openAssetFileDescriptor(resolver, wordListUri);
+ afd = openAssetFileDescriptor(providerClient, wordListUri);
// If we can't open it at all, don't even try a number of times.
if (null == afd) return null;
originalSourceStream = afd.createInputStream();
@@ -284,10 +299,10 @@ public final class BinaryDictionaryFileDumper {
}
wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT,
QUERY_PARAMETER_SUCCESS);
- if (0 >= resolver.delete(wordListUriBuilder.build(), null, null)) {
+ if (0 >= providerClient.delete(wordListUriBuilder.build(), null, null)) {
Log.e(TAG, "Could not have the dictionary pack delete a word list");
}
- BinaryDictionaryGetter.removeFilesWithIdExcept(context, id, finalFile);
+ BinaryDictionaryGetter.removeFilesWithIdExcept(context, wordlistId, finalFile);
// Success! Close files (through the finally{} clause) and return.
return AssetFileAddress.makeFromFileName(finalFileName);
} catch (Exception e) {
@@ -327,8 +342,12 @@ public final class BinaryDictionaryFileDumper {
// as invalid.
wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT,
QUERY_PARAMETER_FAILURE);
- if (0 >= resolver.delete(wordListUriBuilder.build(), null, null)) {
- Log.e(TAG, "In addition, we were unable to delete it.");
+ try {
+ if (0 >= providerClient.delete(wordListUriBuilder.build(), null, null)) {
+ Log.e(TAG, "In addition, we were unable to delete it.");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "In addition, communication with the dictionary provider was cut", e);
}
return null;
}
@@ -345,17 +364,27 @@ public final class BinaryDictionaryFileDumper {
*/
public static List<AssetFileAddress> cacheWordListsFromContentProvider(final Locale locale,
final Context context, final boolean hasDefaultWordList) {
- final ContentResolver resolver = context.getContentResolver();
- final List<WordListInfo> idList = getWordListWordListInfos(locale, context,
- hasDefaultWordList);
- final List<AssetFileAddress> fileAddressList = CollectionUtils.newArrayList();
- for (WordListInfo id : idList) {
- final AssetFileAddress afd = cacheWordList(id.mId, id.mLocale, resolver, context);
- if (null != afd) {
- fileAddressList.add(afd);
+ final ContentProviderClient providerClient = context.getContentResolver().
+ acquireContentProviderClient(getProviderUriBuilder("").build());
+ if (null == providerClient) {
+ Log.e(TAG, "Can't establish communication with the dictionary provider");
+ return CollectionUtils.newArrayList();
+ }
+ try {
+ final List<WordListInfo> idList = getWordListWordListInfos(locale, context,
+ hasDefaultWordList);
+ final ArrayList<AssetFileAddress> fileAddressList = CollectionUtils.newArrayList();
+ for (WordListInfo id : idList) {
+ final AssetFileAddress afd =
+ cacheWordList(id.mId, id.mLocale, providerClient, context);
+ if (null != afd) {
+ fileAddressList.add(afd);
+ }
}
+ return fileAddressList;
+ } finally {
+ providerClient.release();
}
- return fileAddressList;
}
/**
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index a96738b3e..e913f2852 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -68,9 +68,13 @@ final class BinaryDictionaryGetter {
/**
* Generates a unique temporary file name in the app cache directory.
*/
- public static String getTempFileName(String id, Context context) throws IOException {
- return File.createTempFile(DictionaryInfoUtils.replaceFileNameDangerousCharacters(id),
- null).getAbsolutePath();
+ public static String getTempFileName(final String id, final Context context)
+ throws IOException {
+ final String safeId = DictionaryInfoUtils.replaceFileNameDangerousCharacters(id);
+ // If the first argument is less than three chars, createTempFile throws a
+ // RuntimeException. We don't really care about what name we get, so just
+ // put a three-chars prefix makes us safe.
+ return File.createTempFile("xxx" + safeId, null).getAbsolutePath();
}
/**
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 422448edf..50e50233e 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -179,14 +179,13 @@ public final class Constants {
public static final int CODE_DELETE = -4;
public static final int CODE_SETTINGS = -5;
public static final int CODE_SHORTCUT = -6;
- public static final int CODE_ACTION_ENTER = -7;
- public static final int CODE_ACTION_NEXT = -8;
- public static final int CODE_ACTION_PREVIOUS = -9;
- public static final int CODE_LANGUAGE_SWITCH = -10;
- public static final int CODE_RESEARCH = -11;
- public static final int CODE_SHIFT_ENTER = -12;
+ public static final int CODE_ACTION_NEXT = -7;
+ public static final int CODE_ACTION_PREVIOUS = -8;
+ public static final int CODE_LANGUAGE_SWITCH = -9;
+ public static final int CODE_RESEARCH = -10;
+ public static final int CODE_SHIFT_ENTER = -11;
// Code value representing the code is not specified.
- public static final int CODE_UNSPECIFIED = -13;
+ public static final int CODE_UNSPECIFIED = -12;
public static boolean isLetterCode(final int code) {
return code >= CODE_SPACE;
@@ -200,7 +199,6 @@ public final class Constants {
case CODE_DELETE: return "delete";
case CODE_SETTINGS: return "settings";
case CODE_SHORTCUT: return "shortcut";
- case CODE_ACTION_ENTER: return "actionEnter";
case CODE_ACTION_NEXT: return "actionNext";
case CODE_ACTION_PREVIOUS: return "actionPrevious";
case CODE_LANGUAGE_SWITCH: return "languageSwitch";
diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java
index 7df266ef2..c2aade64d 100644
--- a/java/src/com/android/inputmethod/latin/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/DebugSettings.java
@@ -57,7 +57,7 @@ public final class DebugSettings extends PreferenceFragment
if (usabilityStudyPref instanceof CheckBoxPreference) {
final CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref;
checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE,
- ResearchLogger.DEFAULT_USABILITY_STUDY_MODE));
+ LatinImeLogger.getUsabilityStudyMode(prefs)));
checkbox.setSummary(R.string.settings_warning_researcher_mode);
}
final Preference statisticsLoggingPref = findPreference(PREF_STATISTICS_LOGGING);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
index d2a946bf5..dcfa483f8 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
@@ -41,8 +41,6 @@ public class DictionaryInfoUtils {
private static final String RESOURCE_PACKAGE_NAME =
DictionaryInfoUtils.class.getPackage().getName();
private static final String DEFAULT_MAIN_DICT = "main";
- private static final String ID_CATEGORY_SEPARATOR =
- BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR;
private static final String MAIN_DICT_PREFIX = "main_";
// 6 digits - unicode is limited to 21 bits
private static final int MAX_HEX_DIGITS_FOR_CODEPOINT = 6;
@@ -51,24 +49,28 @@ public class DictionaryInfoUtils {
private static final String LOCALE_COLUMN = "locale";
private static final String WORDLISTID_COLUMN = "id";
private static final String LOCAL_FILENAME_COLUMN = "filename";
+ private static final String DESCRIPTION_COLUMN = "description";
private static final String DATE_COLUMN = "date";
private static final String FILESIZE_COLUMN = "filesize";
private static final String VERSION_COLUMN = "version";
+ public final String mId;
public final Locale mLocale;
+ public final String mDescription;
public final AssetFileAddress mFileAddress;
public final int mVersion;
- public final String mId;
- public DictionaryInfo(final Locale locale, final AssetFileAddress fileAddress,
- final int version) {
+ public DictionaryInfo(final String id, final Locale locale, final String description,
+ final AssetFileAddress fileAddress, final int version) {
+ mId = id;
mLocale = locale;
+ mDescription = description;
mFileAddress = fileAddress;
mVersion = version;
- mId = DEFAULT_MAIN_DICT + ID_CATEGORY_SEPARATOR + mLocale;
}
public ContentValues toContentValues() {
final ContentValues values = new ContentValues();
values.put(WORDLISTID_COLUMN, mId);
values.put(LOCALE_COLUMN, mLocale.toString());
+ values.put(DESCRIPTION_COLUMN, mDescription);
values.put(LOCAL_FILENAME_COLUMN, mFileAddress.mFilename);
values.put(DATE_COLUMN,
new File(mFileAddress.mFilename).lastModified() / DateUtils.SECOND_IN_MILLIS);
@@ -283,9 +285,11 @@ public class DictionaryInfoUtils {
final AssetFileAddress fileAddress) {
final FileHeader header = BinaryDictIOUtils.getDictionaryFileHeaderOrNull(
new File(fileAddress.mFilename), fileAddress.mOffset, fileAddress.mLength);
+ final String id = header.getId();
final Locale locale = LocaleUtils.constructLocaleFromString(header.getLocaleString());
+ final String description = header.getDescription();
final String version = header.getVersion();
- return new DictionaryInfo(locale, fileAddress, Integer.parseInt(version));
+ return new DictionaryInfo(id, locale, description, fileAddress, Integer.parseInt(version));
}
private static void addOrUpdateDictInfo(final ArrayList<DictionaryInfo> dictList,
diff --git a/java/src/com/android/inputmethod/latin/InputTypeUtils.java b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
index 2ad619b82..ecb20144b 100644
--- a/java/src/com/android/inputmethod/latin/InputTypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
@@ -106,18 +106,13 @@ public final class InputTypeUtils implements InputType {
}
public static int getImeOptionsActionIdFromEditorInfo(final EditorInfo editorInfo) {
- final int actionId = editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
if ((editorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
return EditorInfo.IME_ACTION_NONE;
} else if (editorInfo.actionLabel != null) {
return IME_ACTION_CUSTOM_LABEL;
} else {
- return actionId;
+ // Note: this is different from editorInfo.actionId, hence "ImeOptionsActionId"
+ return editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
}
}
-
- public static int getConcreteActionIdFromEditorInfo(final EditorInfo editorInfo) {
- final int actionId = getImeOptionsActionIdFromEditorInfo(editorInfo);
- return actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL ? editorInfo.actionId : actionId;
- }
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 73ace2bfa..252fb02c8 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -132,6 +132,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private View mKeyPreviewBackingView;
private View mSuggestionsContainer;
private SuggestionStripView mSuggestionStripView;
+ // Never null
+ private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
@UsedForTesting Suggest mSuggest;
private CompletionInfo[] mApplicationSpecifiedCompletions;
private ApplicationInfo mTargetApplicationInfo;
@@ -165,7 +167,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private boolean mExpectingUpdateSelection;
private int mDeleteCount;
private long mLastKeyTime;
- private int mActionId;
private TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet();
// Member variables for remembering the current device orientation.
@@ -427,7 +428,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
initSuggest();
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().init(this, mKeyboardSwitcher);
+ ResearchLogger.getInstance().init(this, mKeyboardSwitcher, mSuggest);
}
mDisplayOrientation = getResources().getConfiguration().orientation;
@@ -562,6 +563,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mSettings.onDestroy();
unregisterReceiver(mReceiver);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.getInstance().onDestroy();
+ }
// TODO: The experimental version is not supported by the Dictionary Pack Service yet.
if (!ProductionFlag.IS_EXPERIMENTAL) {
unregisterReceiver(mDictionaryPackInstallReceiver);
@@ -729,6 +733,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// otherwise it will clear the suggestion strip.
setPunctuationSuggestions();
}
+ mSuggestedWords = SuggestedWords.EMPTY;
mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart);
@@ -756,7 +761,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mLastSelectionStart = editorInfo.initialSelStart;
mLastSelectionEnd = editorInfo.initialSelEnd;
- mActionId = InputTypeUtils.getConcreteActionIdFromEditorInfo(editorInfo);
mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacePeriodTimer();
@@ -954,6 +958,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
LatinImeLogger.commit();
mKeyboardSwitcher.onHideWindow();
+ if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
+ AccessibleKeyboardViewProxy.getInstance().onHideWindow();
+ }
+
if (TRACE) Debug.stopMethodTracing();
if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
mOptionsDialog.dismiss();
@@ -994,7 +1002,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
false /* isPrediction */);
// When in fullscreen mode, show completions generated by the application
final boolean isAutoCorrection = false;
- setSuggestionStrip(suggestedWords, isAutoCorrection);
+ setSuggestedWords(suggestedWords, isAutoCorrection);
setAutoCorrectionIndicator(isAutoCorrection);
setSuggestionStripShown(true);
if (ProductionFlag.IS_EXPERIMENTAL) {
@@ -1119,7 +1127,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mSettings.getCurrent().mBigramPredictionEnabled) {
clearSuggestionStrip();
} else {
- setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false);
+ setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false);
}
mConnection.resetCachesUponCursorMove(newCursorPosition);
}
@@ -1393,13 +1401,28 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
ResearchLogger.getInstance().onResearchKeySelected(this);
}
break;
- case Constants.CODE_ACTION_ENTER:
- if (EditorInfo.IME_ACTION_NONE != mActionId
- && EditorInfo.IME_ACTION_UNSPECIFIED != mActionId) {
- performEditorAction(mActionId);
- break;
+ case Constants.CODE_ENTER:
+ final EditorInfo editorInfo = getCurrentInputEditorInfo();
+ final int imeOptionsActionId =
+ InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo);
+ if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) {
+ // Either we have an actionLabel and we should performEditorAction with actionId
+ // regardless of its value.
+ performEditorAction(editorInfo.actionId);
+ } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) {
+ // We didn't have an actionLabel, but we had another action to execute.
+ // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast,
+ // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it
+ // means there should be an action and the app didn't bother to set a specific
+ // code for it - presumably it only handles one. It does not have to be treated
+ // in any specific way: anything that is not IME_ACTION_NONE should be sent to
+ // performEditorAction.
+ performEditorAction(imeOptionsActionId);
+ } else {
+ // No action label, and the action from imeOptions is NONE: this is a regular
+ // enter key that should input a carriage return.
+ didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState);
}
- didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState);
break;
case Constants.CODE_SHIFT_ENTER:
didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState);
@@ -1967,8 +1990,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Outside LatinIME, only used by the test suite.
@UsedForTesting
boolean isShowingPunctuationList() {
- if (mSuggestionStripView == null) return false;
- return mSettings.getCurrent().mSuggestPuncList == mSuggestionStripView.getSuggestions();
+ if (mSuggestedWords == null) return false;
+ return mSettings.getCurrent().mSuggestPuncList == mSuggestedWords;
}
private boolean isSuggestionsStripVisible() {
@@ -1984,11 +2007,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
private void clearSuggestionStrip() {
- setSuggestionStrip(SuggestedWords.EMPTY, false);
+ setSuggestedWords(SuggestedWords.EMPTY, false);
setAutoCorrectionIndicator(false);
}
- private void setSuggestionStrip(final SuggestedWords words, final boolean isAutoCorrection) {
+ private void setSuggestedWords(final SuggestedWords words, final boolean isAutoCorrection) {
+ mSuggestedWords = words;
if (mSuggestionStripView != null) {
mSuggestionStripView.setSuggestions(words);
mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection);
@@ -2071,15 +2095,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
private SuggestedWords getOlderSuggestions(final String typedWord) {
- SuggestedWords previousSuggestions = mSuggestionStripView.getSuggestions();
- if (previousSuggestions == mSettings.getCurrent().mSuggestPuncList) {
- previousSuggestions = SuggestedWords.EMPTY;
+ SuggestedWords previousSuggestedWords = mSuggestedWords;
+ if (previousSuggestedWords == mSettings.getCurrent().mSuggestPuncList) {
+ previousSuggestedWords = SuggestedWords.EMPTY;
}
if (typedWord == null) {
- return previousSuggestions;
+ return previousSuggestedWords;
}
final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions =
- SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
+ SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord,
+ previousSuggestedWords);
return new SuggestedWords(typedWordAndPreviousSuggestions,
false /* typedWordValid */,
false /* hasAutoCorrectionCandidate */,
@@ -2101,7 +2126,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mWordComposer.setAutoCorrection(autoCorrection);
final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
- setSuggestionStrip(suggestedWords, isAutoCorrection);
+ setSuggestedWords(suggestedWords, isAutoCorrection);
setAutoCorrectionIndicator(isAutoCorrection);
setSuggestionStripShown(isSuggestionsStripVisible());
}
@@ -2124,7 +2149,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer);
}
if (ProductionFlag.IS_EXPERIMENTAL) {
- final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions();
+ final SuggestedWords suggestedWords = mSuggestedWords;
ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection,
separatorString, mWordComposer.isBatchMode(), suggestedWords);
}
@@ -2149,7 +2174,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// interface
@Override
public void pickSuggestionManually(final int index, final String suggestion) {
- final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions();
+ final SuggestedWords suggestedWords = mSuggestedWords;
// If this is a punctuation picked from the suggestion strip, pass it to onCodeInput
if (suggestion.length() == 1 && isShowingPunctuationList()) {
// Word separators are suggested before the user inputs something.
@@ -2181,6 +2206,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()
&& mApplicationSpecifiedCompletions != null
&& index >= 0 && index < mApplicationSpecifiedCompletions.length) {
+ mSuggestedWords = SuggestedWords.EMPTY;
if (mSuggestionStripView != null) {
mSuggestionStripView.clear();
}
@@ -2236,7 +2262,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
*/
private void commitChosenWord(final String chosenWord, final int commitType,
final String separatorString) {
- final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions();
+ final SuggestedWords suggestedWords = mSuggestedWords;
mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1);
// Add the word to the user history dictionary
@@ -2253,7 +2279,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mSettings.getCurrent().mBigramPredictionEnabled) {
clearSuggestionStrip();
} else {
- setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false);
+ setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false);
}
setAutoCorrectionIndicator(false);
setSuggestionStripShown(isSuggestionsStripVisible());
@@ -2550,6 +2576,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
dialog.show();
}
+ // TODO: can this be removed somehow without breaking the tests?
+ @UsedForTesting
+ /* package for test */ String getFirstSuggestedWord() {
+ return mSuggestedWords.size() > 0 ? mSuggestedWords.getWord(0) : null;
+ }
+
public void debugDumpStateAndCrashWithException(final String context) {
final StringBuilder s = new StringBuilder();
s.append("Target application : ").append(mTargetApplicationInfo.name)
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index e4e8b94b2..3f2b0a3f4 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -37,6 +37,10 @@ public final class LatinImeLogger implements SharedPreferences.OnSharedPreferenc
public static void commit() {
}
+ public static boolean getUsabilityStudyMode(final SharedPreferences prefs) {
+ return false;
+ }
+
public static void onDestroy() {
}
diff --git a/java/src/com/android/inputmethod/latin/LocaleUtils.java b/java/src/com/android/inputmethod/latin/LocaleUtils.java
index fcf727041..5fde8158a 100644
--- a/java/src/com/android/inputmethod/latin/LocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/LocaleUtils.java
@@ -180,14 +180,15 @@ public final class LocaleUtils {
synchronized (sLockForRunInLocale) {
final Configuration conf = res.getConfiguration();
final Locale oldLocale = conf.locale;
+ final boolean needsChange = (newLocale != null && !newLocale.equals(oldLocale));
try {
- if (newLocale != null && !newLocale.equals(oldLocale)) {
+ if (needsChange) {
conf.locale = newLocale;
res.updateConfiguration(conf, null);
}
return job(res);
} finally {
- if (newLocale != null && !newLocale.equals(oldLocale)) {
+ if (needsChange) {
conf.locale = oldLocale;
res.updateConfiguration(conf, null);
}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 02b44c7f6..435074bdb 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.preference.PreferenceManager;
@@ -64,6 +65,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_GESTURE_PREVIEW_TRAIL = "pref_gesture_preview_trail";
public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT =
"pref_gesture_floating_preview_text";
+ public static final String PREF_SHOW_SETUP_WIZARD_ICON = "pref_show_setup_wizard_icon";
public static final String PREF_INPUT_LANGUAGE = "input_language";
public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
@@ -260,4 +262,16 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static boolean readUseFullscreenMode(final Resources res) {
return res.getBoolean(R.bool.config_use_fullscreen_mode);
}
+
+ public static boolean readShowSetupWizardIcon(final SharedPreferences prefs,
+ final Context context) {
+ if (!prefs.contains(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) {
+ final ApplicationInfo appInfo = context.getApplicationInfo();
+ final boolean isApplicationInSystemImage =
+ (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ // Default value
+ return !isApplicationInSystemImage;
+ }
+ return prefs.getBoolean(Settings.PREF_SHOW_SETUP_WIZARD_ICON, false);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java
index edd064c0b..4c90e485a 100644
--- a/java/src/com/android/inputmethod/latin/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java
@@ -31,6 +31,7 @@ import android.preference.PreferenceScreen;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
import com.android.inputmethodcommon.InputMethodSettingsFragment;
public final class SettingsFragment extends InputMethodSettingsFragment
@@ -155,6 +156,10 @@ public final class SettingsFragment extends InputMethodSettingsFragment
removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen());
}
+ final CheckBoxPreference showSetupWizardIcon =
+ (CheckBoxPreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON);
+ showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, context));
+
setupKeyLongpressTimeoutSettings(prefs, res);
setupKeypressVibrationDurationSettings(prefs, res);
setupKeypressSoundVolumeSettings(prefs, res);
@@ -196,6 +201,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final boolean gestureInputEnabled = Settings.readGestureInputEnabled(prefs, res);
setPreferenceEnabled(Settings.PREF_GESTURE_PREVIEW_TRAIL, gestureInputEnabled);
setPreferenceEnabled(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, gestureInputEnabled);
+ } else if (key.equals(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) {
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(getActivity());
}
ensureConsistencyOfAutoCorrectionSettings();
updateVoiceModeSummary();
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
index 81bc9f5d7..528028328 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
@@ -263,9 +263,10 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
UserHistoryDictIOUtils.readDictionaryBinary(
new UserHistoryDictIOUtils.ByteArrayWrapper(buffer), listener);
} catch (FileNotFoundException e) {
- Log.e(TAG, "when loading: file not found" + e);
+ // This is an expected condition: we don't have a user history dictionary for this
+ // language yet. It will be created sometime later.
} catch (IOException e) {
- Log.e(TAG, "IOException when open bytebuffer: " + e);
+ Log.e(TAG, "IOException on opening a bytebuffer", e);
} finally {
if (inStream != null) {
try {
@@ -328,7 +329,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
Thread.sleep(15000);
Log.w(TAG, "End stress in closing");
} catch (InterruptedException e) {
- Log.e(TAG, "In stress test: " + e);
+ Log.e(TAG, "In stress test", e);
}
}
@@ -343,7 +344,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
out.flush();
out.close();
} catch (IOException e) {
- Log.e(TAG, "IO Exception while writing file: " + e);
+ Log.e(TAG, "IO Exception while writing file", e);
} finally {
if (out != null) {
try {
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index acfcd5354..7a604dc6a 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -28,6 +28,7 @@ import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import java.io.BufferedReader;
@@ -77,6 +78,7 @@ public final class Utils {
private RingCharBuffer() {
// Intentional empty constructor for singleton.
}
+ @UsedForTesting
public static RingCharBuffer getInstance() {
return sRingCharBuffer;
}
@@ -93,6 +95,7 @@ public final class Utils {
return ret < 0 ? ret + BUFSIZE : ret;
}
// TODO: accept code points
+ @UsedForTesting
public void push(char c, int x, int y) {
if (!mEnabled) return;
mCharBuf[mEnd] = c;
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 31f616dd9..f7cb4346a 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
@@ -177,7 +178,8 @@ public final class WordComposer {
/**
* Internal method to retrieve reasonable proximity info for a character.
*/
- private void addKeyInfo(final int codePoint, final Keyboard keyboard) {
+ @UsedForTesting
+ public void addKeyInfo(final int codePoint, final Keyboard keyboard) {
final int x, y;
final Key key;
if (keyboard != null && (key = keyboard.getKey(codePoint)) != null) {
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index 83acca874..e1e5e5500 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -258,6 +258,8 @@ public final class FormatSpec {
public final FormatOptions mFormatOptions;
private static final String DICTIONARY_VERSION_ATTRIBUTE = "version";
private static final String DICTIONARY_LOCALE_ATTRIBUTE = "locale";
+ private static final String DICTIONARY_ID_ATTRIBUTE = "dictionary";
+ private static final String DICTIONARY_DESCRIPTION_ATTRIBUTE = "description";
public FileHeader(final int headerSize, final DictionaryOptions dictionaryOptions,
final FormatOptions formatOptions) {
mHeaderSize = headerSize;
@@ -274,6 +276,18 @@ public final class FormatSpec {
public String getVersion() {
return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_VERSION_ATTRIBUTE);
}
+
+ // Helper method to get the dictionary ID as a String
+ public String getId() {
+ return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_ID_ATTRIBUTE);
+ }
+
+ // Helper method to get the description
+ public String getDescription() {
+ // TODO: Right now each dictionary file comes with a description in its own language.
+ // It will display as is no matter the device's locale. It should be internationalized.
+ return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_DESCRIPTION_ATTRIBUTE);
+ }
}
private FormatSpec() {
diff --git a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
new file mode 100644
index 000000000..1b893a65d
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.setup;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.android.inputmethod.compat.IntentCompatUtils;
+import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.Settings;
+
+/**
+ * This class detects the {@link Intent#ACTION_MY_PACKAGE_REPLACED} broadcast intent when this IME
+ * package has been replaced by a newer version of the same package. This class also detects
+ * {@link Intent#ACTION_BOOT_COMPLETED} and {@link Intent#ACTION_USER_INITIALIZE} broadcast intent.
+ *
+ * If this IME has already been installed in the system image and a new version of this IME has
+ * been installed, {@link Intent#ACTION_MY_PACKAGE_REPLACED} is received by this receiver and it
+ * will hide the setup wizard's icon.
+ *
+ * If this IME has already been installed in the data partition and a new version of this IME has
+ * been installed, {@link Intent#ACTION_MY_PACKAGE_REPLACED} is received by this receiver but it
+ * will not hide the setup wizard's icon, and the icon will appear on the launcher.
+ *
+ * If this IME hasn't been installed yet and has been newly installed, no
+ * {@link Intent#ACTION_MY_PACKAGE_REPLACED} will be sent and the setup wizard's icon will appear
+ * on the launcher.
+ *
+ * When the device has been booted, {@link Intent#ACTION_BOOT_COMPLETED} is received by this
+ * receiver and it checks whether the setup wizard's icon should be appeared or not on the launcher
+ * depending on which partition this IME is installed.
+ *
+ * When a multiuser account has been created, {@link Intent#ACTION_USER_INITIALIZE} is received
+ * by this receiver and it checks the whether the setup wizard's icon should be appeared or not on
+ * the launcher depending on which partition this IME is installed.
+ */
+public final class LauncherIconVisibilityManager extends BroadcastReceiver {
+ private static final String TAG = LauncherIconVisibilityManager.class.getSimpleName();
+
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ if (shouldHandleThisIntent(intent, context)) {
+ updateSetupWizardIconVisibility(context);
+ }
+
+ // The process that hosts this broadcast receiver is invoked and remains alive even after
+ // 1) the package has been re-installed, 2) the device has been booted,
+ // 3) a multiuser has been created.
+ // There is no good reason to keep the process alive if this IME isn't a current IME.
+ RichInputMethodManager.init(context);
+ if (!SetupActivity.isThisImeCurrent(context)) {
+ final int myPid = Process.myPid();
+ Log.i(TAG, "Killing my process: pid=" + myPid);
+ Process.killProcess(myPid);
+ }
+ }
+
+ private static boolean shouldHandleThisIntent(final Intent intent, final Context context) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(action)) {
+ Log.i(TAG, "Package has been replaced: " + context.getPackageName());
+ return true;
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ Log.i(TAG, "Boot has been completed");
+ return true;
+ } else if (IntentCompatUtils.has_ACTION_USER_INITIALIZE(intent)) {
+ Log.i(TAG, "User initialize");
+ return true;
+ }
+ return false;
+ }
+
+ public static void updateSetupWizardIconVisibility(final Context context) {
+ final ComponentName setupWizardActivity = new ComponentName(context, SetupActivity.class);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ final boolean stateHasSet;
+ if (Settings.readShowSetupWizardIcon(prefs, context)) {
+ stateHasSet = setActivityState(context, setupWizardActivity,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+ Log.i(TAG, (stateHasSet ? "Enable activity: " : "Activity has already been enabled: ")
+ + setupWizardActivity);
+ } else {
+ stateHasSet = setActivityState(context, setupWizardActivity,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+ Log.i(TAG, (stateHasSet ? "Disable activity: " : "Activity has already been disabled: ")
+ + setupWizardActivity);
+ }
+ }
+
+ private static boolean setActivityState(final Context context,
+ final ComponentName activityComponent, final int activityState) {
+ final PackageManager pm = context.getPackageManager();
+ final int activityComponentState = pm.getComponentEnabledSetting(activityComponent);
+ if (activityComponentState == activityState) {
+ return false;
+ }
+ pm.setComponentEnabledSetting(
+ activityComponent, activityState, PackageManager.DONT_KILL_APP);
+ return true;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
index fab894584..e009fbc39 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
@@ -17,23 +17,341 @@
package com.android.inputmethod.latin.setup;
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.Message;
+import android.provider.Settings;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
+import com.android.inputmethod.compat.TextViewCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
+import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.SettingsActivity;
+import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+
+import java.util.HashMap;
public final class SetupActivity extends Activity {
+ private SetupStepIndicatorView mStepIndicatorView;
+ private final SetupStepGroup mSetupSteps = new SetupStepGroup();
+ private static final String STATE_STEP = "step";
+ private int mStepNumber;
+ private static final int STEP_1 = 1;
+ private static final int STEP_2 = 2;
+ private static final int STEP_3 = 3;
+
+ private final SettingsPoolingHandler mHandler = new SettingsPoolingHandler(this);
+
+ static final class SettingsPoolingHandler extends StaticInnerHandlerWrapper<SetupActivity> {
+ private static final int MSG_POLLING_IME_SETTINGS = 0;
+ private static final long IME_SETTINGS_POLLING_INTERVAL = 200;
+
+ public SettingsPoolingHandler(final SetupActivity outerInstance) {
+ super(outerInstance);
+ }
+
+ @Override
+ public void handleMessage(final Message msg) {
+ final SetupActivity setupActivity = getOuterInstance();
+ switch (msg.what) {
+ case MSG_POLLING_IME_SETTINGS:
+ if (SetupActivity.isThisImeEnabled(setupActivity)) {
+ setupActivity.invokeSetupWizardOfThisIme();
+ return;
+ }
+ startPollingImeSettings();
+ break;
+ }
+ }
+
+ public void startPollingImeSettings() {
+ sendMessageDelayed(obtainMessage(MSG_POLLING_IME_SETTINGS),
+ IME_SETTINGS_POLLING_INTERVAL);
+ }
+
+ public void cancelPollingImeSettings() {
+ removeMessages(MSG_POLLING_IME_SETTINGS);
+ }
+ }
+
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(final Bundle savedInstanceState) {
+ setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar);
super.onCreate(savedInstanceState);
- // TODO: Implement setup wizard.
+ setContentView(R.layout.setup_wizard);
+
+ RichInputMethodManager.init(this);
+
+ if (savedInstanceState == null) {
+ mStepNumber = determineSetupStepNumber();
+ } else {
+ mStepNumber = savedInstanceState.getInt(STATE_STEP);
+ }
+
+ if (mStepNumber == STEP_3) {
+ // This IME already has been enabled and set as current IME.
+ // TODO: Implement tutorial.
+ invokeSettingsOfThisIme();
+ finish();
+ return;
+ }
+
+ // TODO: Use sans-serif-thin font family depending on the system locale white list and
+ // the SDK version.
+ final TextView titleView = (TextView)findViewById(R.id.setup_title);
+ titleView.setText(getString(R.string.setup_title, getString(R.string.english_ime_name)));
+
+ mStepIndicatorView = (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
+
+ final SetupStep step1 = new SetupStep(findViewById(R.id.setup_step1),
+ R.string.setup_step1_title, R.string.setup_step1_instruction,
+ R.drawable.ic_settings_language, R.string.language_settings);
+ step1.setAction(new Runnable() {
+ @Override
+ public void run() {
+ invokeLanguageAndInputSettings();
+ mHandler.startPollingImeSettings();
+ }
+ });
+ mSetupSteps.addStep(STEP_1, step1);
+
+ final SetupStep step2 = new SetupStep(findViewById(R.id.setup_step2),
+ R.string.setup_step2_title, R.string.setup_step2_instruction,
+ 0 /* actionIcon */, R.string.select_input_method);
+ step2.setAction(new Runnable() {
+ @Override
+ public void run() {
+ // Invoke input method picker.
+ RichInputMethodManager.getInstance().getInputMethodManager()
+ .showInputMethodPicker();
+ }
+ });
+ mSetupSteps.addStep(STEP_2, step2);
+
+ final SetupStep step3 = new SetupStep(findViewById(R.id.setup_step3),
+ R.string.setup_step3_title, 0 /* instruction */,
+ R.drawable.sym_keyboard_language_switch, R.string.setup_step3_instruction);
+ step3.setAction(new Runnable() {
+ @Override
+ public void run() {
+ invokeSubtypeEnablerOfThisIme();
+ }
+ });
+ mSetupSteps.addStep(STEP_3, step3);
+ }
+
+ private void invokeSetupWizardOfThisIme() {
+ final Intent intent = new Intent();
+ intent.setClass(this, SetupActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ private void invokeSettingsOfThisIme() {
final Intent intent = new Intent();
intent.setClass(this, SettingsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
- finish();
+ }
+
+ private void invokeLanguageAndInputSettings() {
+ final Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ startActivity(intent);
+ }
+
+ private void invokeSubtypeEnablerOfThisIme() {
+ final InputMethodInfo imi =
+ RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
+ final Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, imi.getId());
+ startActivity(intent);
+ }
+
+ /**
+ * Check if the IME specified by the context is enabled.
+ * Note that {@link RichInputMethodManager} must have been initialized before calling this
+ * method.
+ *
+ * @param context package context of the IME to be checked.
+ * @return true if this IME is enabled.
+ */
+ public static boolean isThisImeEnabled(final Context context) {
+ final String packageName = context.getPackageName();
+ final InputMethodManager imm = RichInputMethodManager.getInstance().getInputMethodManager();
+ for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) {
+ if (packageName.equals(imi.getPackageName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the IME specified by the context is the current IME.
+ * Note that {@link RichInputMethodManager} must have been initialized before calling this
+ * method.
+ *
+ * @param context package context of the IME to be checked.
+ * @return true if this IME is the current IME.
+ */
+ public static boolean isThisImeCurrent(final Context context) {
+ final InputMethodInfo myImi =
+ RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
+ final String currentImeId = Settings.Secure.getString(
+ context.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ return myImi.getId().equals(currentImeId);
+ }
+
+ private int determineSetupStepNumber() {
+ mHandler.cancelPollingImeSettings();
+ if (!isThisImeEnabled(this)) {
+ return STEP_1;
+ }
+ if (!isThisImeCurrent(this)) {
+ return STEP_2;
+ }
+ return STEP_3;
+ }
+
+ @Override
+ protected void onSaveInstanceState(final Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(STATE_STEP, mStepNumber);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(final Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ mStepNumber = savedInstanceState.getInt(STATE_STEP);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mStepNumber = determineSetupStepNumber();
+ }
+
+ @Override
+ protected void onRestart() {
+ super.onRestart();
+ mStepNumber = determineSetupStepNumber();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateSetupStepView();
+ }
+
+ @Override
+ public void onWindowFocusChanged(final boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (!hasFocus) {
+ return;
+ }
+ mStepNumber = determineSetupStepNumber();
+ updateSetupStepView();
+ }
+
+ private void updateSetupStepView() {
+ final int layoutDirection = ViewCompatUtils.getLayoutDirection(mStepIndicatorView);
+ mStepIndicatorView.setIndicatorPosition(
+ getIndicatorPosition(mStepNumber, mSetupSteps.getTotalStep(), layoutDirection));
+ mSetupSteps.enableStep(mStepNumber);
+ }
+
+ private static float getIndicatorPosition(final int step, final int totalStep,
+ final int layoutDirection) {
+ final float pos = ((step - STEP_1) * 2 + 1) / (float)(totalStep * 2);
+ return (layoutDirection == ViewCompatUtils.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos;
+ }
+
+ static final class SetupStep implements View.OnClickListener {
+ private final View mRootView;
+ private final TextView mActionLabel;
+ private Runnable mAction;
+
+ public SetupStep(final View rootView, final int title, final int instruction,
+ final int actionIcon, final int actionLabel) {
+ mRootView = rootView;
+ final Resources res = rootView.getResources();
+ final String applicationName = res.getString(R.string.english_ime_name);
+
+ final TextView titleView = (TextView)rootView.findViewById(R.id.setup_step_title);
+ titleView.setText(res.getString(title, applicationName));
+
+ final TextView instructionView = (TextView)rootView.findViewById(
+ R.id.setup_step_instruction);
+ if (instruction == 0) {
+ instructionView.setVisibility(View.GONE);
+ } else {
+ instructionView.setText(res.getString(instruction, applicationName));
+ }
+
+ mActionLabel = (TextView)rootView.findViewById(R.id.setup_step_action_label);
+ mActionLabel.setText(res.getString(actionLabel));
+ if (actionIcon == 0) {
+ final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
+ ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
+ } else {
+ final int overrideColor = res.getColor(R.color.setup_text_action);
+ final Drawable icon = res.getDrawable(actionIcon);
+ icon.setColorFilter(overrideColor, PorterDuff.Mode.MULTIPLY);
+ icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
+ TextViewCompatUtils.setCompoundDrawablesRelative(
+ mActionLabel, icon, null, null, null);
+ }
+ }
+
+ public void setEnabled(final boolean enabled) {
+ mRootView.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ }
+
+ public void setAction(final Runnable action) {
+ mActionLabel.setOnClickListener(this);
+ mAction = action;
+ }
+
+ @Override
+ public void onClick(final View v) {
+ if (mAction != null) {
+ mAction.run();
+ }
+ }
+ }
+
+ static final class SetupStepGroup {
+ private final HashMap<Integer, SetupStep> mGroup = CollectionUtils.newHashMap();
+
+ public void addStep(final int stepNo, final SetupStep step) {
+ mGroup.put(stepNo, step);
+ }
+
+ public void enableStep(final int enableStepNo) {
+ for (final Integer stepNo : mGroup.keySet()) {
+ final SetupStep step = mGroup.get(stepNo);
+ step.setEnabled(stepNo == enableStepNo);
+ }
+ }
+
+ public int getTotalStep() {
+ return mGroup.size();
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
new file mode 100644
index 000000000..077a21793
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.setup;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.inputmethod.latin.R;
+
+public final class SetupStepIndicatorView extends View {
+ private final Path mIndicatorPath = new Path();
+ private final Paint mIndicatorPaint = new Paint();
+ private float mXRatio;
+
+ public SetupStepIndicatorView(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ mIndicatorPaint.setColor(getResources().getColor(R.color.setup_step_background));
+ mIndicatorPaint.setStyle(Paint.Style.FILL);
+ }
+
+ public void setIndicatorPosition(final float xRatio) {
+ mXRatio = xRatio;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(final Canvas canvas) {
+ super.onDraw(canvas);
+ final int xPos = (int)(getWidth() * mXRatio);
+ final int height = getHeight();
+ mIndicatorPath.rewind();
+ mIndicatorPath.moveTo(xPos, 0);
+ mIndicatorPath.lineTo(xPos + height, height);
+ mIndicatorPath.lineTo(xPos - height, height);
+ mIndicatorPath.close();
+ canvas.drawPath(mIndicatorPath, mIndicatorPaint);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index bc51d5d62..5a29eee4e 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -644,10 +644,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return false;
}
- public SuggestedWords getSuggestions() {
- return mSuggestedWords;
- }
-
public void clear() {
mSuggestionsStrip.removeAllViews();
removeAllViews();
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index 1a9a720f3..839e2b7ba 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -16,7 +16,6 @@
package com.android.inputmethod.research;
-import android.content.SharedPreferences;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.JsonWriter;
@@ -45,7 +44,7 @@ import java.util.List;
* will not violate the user's privacy. Checks for this may include whether other LogUnits have
* been published recently, or whether the LogUnit contains numbers, etc.
*/
-/* package */ class LogUnit {
+public class LogUnit {
private static final String TAG = LogUnit.class.getSimpleName();
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
@@ -151,10 +150,10 @@ import java.util.List;
continue;
}
// Only retrieve the jsonWriter if we need to. If we don't get this far, then
- // researchLog.getValidJsonWriterLocked() will not ever be called, and the file
- // will not have been opened for writing.
+ // researchLog.getInitializedJsonWriterLocked() will not ever be called, and the
+ // file will not have been opened for writing.
if (jsonWriter == null) {
- jsonWriter = researchLog.getValidJsonWriterLocked();
+ jsonWriter = researchLog.getInitializedJsonWriterLocked();
outputLogUnitStart(jsonWriter, canIncludePrivateData);
}
logStatement.outputToLocked(jsonWriter, mTimeList.get(i), mValuesList.get(i));
diff --git a/java/src/com/android/inputmethod/research/LoggingUtils.java b/java/src/com/android/inputmethod/research/LoggingUtils.java
new file mode 100644
index 000000000..1261d6780
--- /dev/null
+++ b/java/src/com/android/inputmethod/research/LoggingUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.research;
+
+import android.view.MotionEvent;
+
+/* package */ class LoggingUtils {
+ private LoggingUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ /* package */ static String getMotionEventActionTypeString(final int actionType) {
+ switch (actionType) {
+ case MotionEvent.ACTION_CANCEL: return "CANCEL";
+ case MotionEvent.ACTION_UP: return "UP";
+ case MotionEvent.ACTION_DOWN: return "DOWN";
+ case MotionEvent.ACTION_POINTER_UP: return "POINTER_UP";
+ case MotionEvent.ACTION_POINTER_DOWN: return "POINTER_DOWN";
+ case MotionEvent.ACTION_MOVE: return "MOVE";
+ case MotionEvent.ACTION_OUTSIDE: return "OUTSIDE";
+ default: return "ACTION_" + actionType;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java
index 3a87bf1df..9aa60f859 100644
--- a/java/src/com/android/inputmethod/research/MainLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.research;
import android.util.Log;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.Suggest;
import com.android.inputmethod.latin.define.ProductionFlag;
@@ -64,16 +65,11 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
// The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams.
public static final int N_GRAM_SIZE = 2;
- // Whether all words should be recorded, leaving unsampled word between bigrams. Useful for
- // testing.
- /* package for test */ static final boolean IS_LOGGING_EVERYTHING = false
- && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
-
- // The number of words between n-grams to omit from the log.
- private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES =
- IS_LOGGING_EVERYTHING ? 0 : (DEBUG ? 2 : 18);
-
- private Suggest mSuggest;
+ // TODO: Remove dependence on Suggest, and pass in Dictionary as a parameter to an appropriate
+ // method.
+ private final Suggest mSuggest;
+ @UsedForTesting
+ private Dictionary mDictionaryForTesting;
private boolean mIsStopping = false;
/* package for test */ int mNumWordsBetweenNGrams;
@@ -82,15 +78,25 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
// after a sample is taken.
/* package for test */ int mNumWordsUntilSafeToSample;
- public MainLogBuffer() {
- super(N_GRAM_SIZE + DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES);
- mNumWordsBetweenNGrams = DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES;
- final Random random = new Random();
- mNumWordsUntilSafeToSample = DEBUG ? 0 : random.nextInt(mNumWordsBetweenNGrams + 1);
+ public MainLogBuffer(final int wordsBetweenSamples, final int numInitialWordsToIgnore,
+ final Suggest suggest) {
+ super(N_GRAM_SIZE + wordsBetweenSamples);
+ mNumWordsBetweenNGrams = wordsBetweenSamples;
+ mNumWordsUntilSafeToSample = DEBUG ? 0 : numInitialWordsToIgnore;
+ mSuggest = suggest;
}
- public void setSuggest(final Suggest suggest) {
- mSuggest = suggest;
+ @UsedForTesting
+ /* package for test */ void setDictionaryForTesting(final Dictionary dictionary) {
+ mDictionaryForTesting = dictionary;
+ }
+
+ private Dictionary getDictionary() {
+ if (mDictionaryForTesting != null) {
+ return mDictionaryForTesting;
+ }
+ if (mSuggest == null || !mSuggest.hasMainDictionary()) return null;
+ return mSuggest.getMainDictionary();
}
public void resetWordCounter() {
@@ -114,7 +120,7 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
*/
private boolean isSafeNGram(final ArrayList<LogUnit> logUnits, final int minNGramSize) {
// Bypass privacy checks when debugging.
- if (IS_LOGGING_EVERYTHING) {
+ if (ResearchLogger.IS_LOGGING_EVERYTHING) {
if (mIsStopping) {
return true;
}
@@ -137,16 +143,13 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
if (mNumWordsUntilSafeToSample > 0) {
return false;
}
- if (mSuggest == null || !mSuggest.hasMainDictionary()) {
- // Main dictionary is unavailable. Since we cannot check it, we cannot tell if a
- // word is out-of-vocabulary or not. Therefore, we must judge the entire buffer
- // contents to potentially pose a privacy risk.
- return false;
- }
// Reload the dictionary in case it has changed (e.g., because the user has changed
// languages).
- final Dictionary dictionary = mSuggest.getMainDictionary();
+ final Dictionary dictionary = getDictionary();
if (dictionary == null) {
+ // Main dictionary is unavailable. Since we cannot check it, we cannot tell if a
+ // word is out-of-vocabulary or not. Therefore, we must judge the entire buffer
+ // contents to potentially pose a privacy risk.
return false;
}
@@ -220,10 +223,10 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
final boolean canIncludePrivateData);
@Override
- protected void shiftOutWords(int numWords) {
- int oldNumActualWords = getNumActualWords();
+ protected void shiftOutWords(final int numWords) {
+ final int oldNumActualWords = getNumActualWords();
super.shiftOutWords(numWords);
- int numWordsShifted = oldNumActualWords - getNumActualWords();
+ final int numWordsShifted = oldNumActualWords - getNumActualWords();
mNumWordsUntilSafeToSample -= numWordsShifted;
if (DEBUG) {
Log.d(TAG, "wordsUntilSafeToSample now at " + mNumWordsUntilSafeToSample);
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 5114977d8..9016e23b3 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -38,12 +38,19 @@ import java.util.concurrent.TimeUnit;
/**
* Logs the use of the LatinIME keyboard.
*
- * This class logs operations on the IME keyboard, including what the user has typed.
- * Data is stored locally in a file in app-specific storage.
+ * This class logs operations on the IME keyboard, including what the user has typed. Data is
+ * written to a {@link JsonWriter}, which will write to a local file.
+ *
+ * The JsonWriter is created on-demand by calling {@link #getInitializedJsonWriterLocked}.
+ *
+ * This class uses an executor to perform file-writing operations on a separate thread. It also
+ * tries to avoid creating unnecessary files if there is nothing to write. It also handles
+ * flushing, making sure it happens, but not too frequently.
*
* This functionality is off by default. See {@link ProductionFlag#IS_EXPERIMENTAL}.
*/
public class ResearchLog {
+ // TODO: Automatically initialize the JsonWriter rather than requiring the caller to manage it.
private static final String TAG = ResearchLog.class.getSimpleName();
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
private static final long FLUSH_DELAY_IN_MS = 1000 * 5;
@@ -87,6 +94,12 @@ public class ResearchLog {
mContext = context;
}
+ /**
+ * Waits for any publication requests to finish and closes the {@link JsonWriter} used for
+ * output.
+ *
+ * See class comment for details about {@code JsonWriter} construction.
+ */
public synchronized void close(final Runnable onClosed) {
mExecutor.submit(new Callable<Object>() {
@Override
@@ -94,20 +107,15 @@ public class ResearchLog {
try {
if (mHasWrittenData) {
mJsonWriter.endArray();
- mJsonWriter.flush();
- mJsonWriter.close();
- if (DEBUG) {
- Log.d(TAG, "wrote log to " + mFile);
- }
mHasWrittenData = false;
- } else {
- if (DEBUG) {
- Log.d(TAG, "close() called, but no data, not outputting");
- }
+ }
+ mJsonWriter.flush();
+ mJsonWriter.close();
+ if (DEBUG) {
+ Log.d(TAG, "wrote log to " + mFile);
}
} catch (Exception e) {
- Log.d(TAG, "error when closing ResearchLog:");
- e.printStackTrace();
+ Log.d(TAG, "error when closing ResearchLog:", e);
} finally {
if (mFile != null && mFile.exists()) {
mFile.setWritable(false, false);
@@ -125,6 +133,12 @@ public class ResearchLog {
private boolean mIsAbortSuccessful;
+ /**
+ * Waits for publication requests to finish, closes the {@link JsonWriter}, but then deletes the
+ * backing file used for output.
+ *
+ * See class comment for details about {@code JsonWriter} construction.
+ */
public synchronized void abort() {
mExecutor.submit(new Callable<Object>() {
@Override
@@ -184,6 +198,12 @@ public class ResearchLog {
mFlushFuture = mExecutor.schedule(mFlushCallable, FLUSH_DELAY_IN_MS, TimeUnit.MILLISECONDS);
}
+ /**
+ * Queues up {@code logUnit} to be published in the background.
+ *
+ * @param logUnit the {@link LogUnit} to be published
+ * @param canIncludePrivateData whether private data in the LogUnit should be included
+ */
public synchronized void publish(final LogUnit logUnit, final boolean canIncludePrivateData) {
try {
mExecutor.submit(new Callable<Object>() {
@@ -206,29 +226,39 @@ public class ResearchLog {
* Return a JsonWriter for this ResearchLog. It is initialized the first time this method is
* called. The cached value is returned in future calls.
*/
- public JsonWriter getValidJsonWriterLocked() {
+ public JsonWriter getInitializedJsonWriterLocked() {
+ if (mJsonWriter != NULL_JSON_WRITER || mFile == null) return mJsonWriter;
try {
- if (mJsonWriter == NULL_JSON_WRITER && mFile != null) {
- final FileOutputStream fos =
- mContext.openFileOutput(mFile.getName(), Context.MODE_PRIVATE);
- mJsonWriter = new JsonWriter(new BufferedWriter(new OutputStreamWriter(fos)));
- mJsonWriter.beginArray();
+ final JsonWriter jsonWriter = createJsonWriter(mContext, mFile);
+ if (jsonWriter != null) {
+ jsonWriter.beginArray();
+ mJsonWriter = jsonWriter;
mHasWrittenData = true;
}
- } catch (IOException e) {
- e.printStackTrace();
- Log.w(TAG, "Error in JsonWriter; disabling logging");
+ } catch (final IOException e) {
+ Log.w(TAG, "Error in JsonWriter; disabling logging", e);
try {
mJsonWriter.close();
- } catch (IllegalStateException e1) {
+ } catch (final IllegalStateException e1) {
// Assume that this is just the json not being terminated properly.
// Ignore
- } catch (IOException e1) {
- e1.printStackTrace();
+ } catch (final IOException e1) {
+ Log.w(TAG, "Error in closing JsonWriter; disabling logging", e1);
} finally {
mJsonWriter = NULL_JSON_WRITER;
}
}
return mJsonWriter;
}
+
+ /**
+ * Create the JsonWriter to write the ResearchLog to.
+ *
+ * This method may be overriden in testing to redirect the output.
+ */
+ /* package for test */ JsonWriter createJsonWriter(final Context context, final File file)
+ throws IOException {
+ return new JsonWriter(new BufferedWriter(new OutputStreamWriter(
+ context.openFileOutput(file.getName(), Context.MODE_PRIVATE))));
+ }
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 45212913e..e705ddda1 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -88,6 +88,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.Random;
import java.util.UUID;
/**
@@ -121,31 +122,36 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// field holds a channel name, the developer does not have to re-enter it when using the
// feedback mechanism to generate multiple tests.
private static final boolean FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD = false;
- public static final boolean DEFAULT_USABILITY_STUDY_MODE = false;
/* package */ static boolean sIsLogging = false;
private static final int OUTPUT_FORMAT_VERSION = 5;
private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
- private static final String PREF_RESEARCH_HAS_SEEN_SPLASH = "pref_research_has_seen_splash";
/* package */ static final String LOG_FILENAME_PREFIX = "researchLog";
private static final String LOG_FILENAME_SUFFIX = ".txt";
/* package */ static final String USER_RECORDING_FILENAME_PREFIX = "recording";
private static final String USER_RECORDING_FILENAME_SUFFIX = ".txt";
private static final SimpleDateFormat TIMESTAMP_DATEFORMAT =
new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US);
+ // Whether all words should be recorded, leaving unsampled word between bigrams. Useful for
+ // testing.
+ /* package for test */ static final boolean IS_LOGGING_EVERYTHING = false
+ && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
+ // The number of words between n-grams to omit from the log.
+ private static final int NUMBER_OF_WORDS_BETWEEN_SAMPLES =
+ IS_LOGGING_EVERYTHING ? 0 : (DEBUG ? 2 : 18);
+
// Whether to show an indicator on the screen that logging is on. Currently a very small red
// dot in the lower right hand corner. Most users should not notice it.
private static final boolean IS_SHOWING_INDICATOR = true;
// Change the default indicator to something very visible. Currently two red vertical bars on
// either side of they keyboard.
private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false ||
- (MainLogBuffer.IS_LOGGING_EVERYTHING && ProductionFlag.IS_EXPERIMENTAL_DEBUG);
+ (IS_LOGGING_EVERYTHING && ProductionFlag.IS_EXPERIMENTAL_DEBUG);
// FEEDBACK_WORD_BUFFER_SIZE should add 1 because it must also hold the feedback LogUnit itself.
public static final int FEEDBACK_WORD_BUFFER_SIZE = (Integer.MAX_VALUE - 1) + 1;
// constants related to specific log points
private static final String WHITESPACE_SEPARATORS = " \t\n\r";
private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1
- private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid";
private static final String PREF_RESEARCH_SAVED_CHANNEL = "pref_research_saved_channel";
private static final ResearchLogger sInstance = new ResearchLogger();
@@ -153,7 +159,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private static String sAllowedAccountDomain = null;
// to write to a different filename, e.g., for testing, set mFile before calling start()
/* package */ File mFilesDir;
- /* package */ String mUUIDString;
/* package */ ResearchLog mMainResearchLog;
// mFeedbackLog records all events for the session, private or not (excepting
// passwords). It is written to permanent storage only if the user explicitly commands
@@ -199,7 +204,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private Intent mUploadIntent;
private Intent mUploadNowIntent;
- private LogUnit mCurrentLogUnit = new LogUnit();
+ /* package for test */ LogUnit mCurrentLogUnit = new LogUnit();
// Gestured or tapped words may be committed after the gesture of the next word has started.
// To ensure that the gesture data of the next word is not associated with the previous word,
@@ -228,50 +233,44 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return sInstance;
}
- public void init(final LatinIME latinIME, final KeyboardSwitcher keyboardSwitcher) {
+ public void init(final LatinIME latinIME, final KeyboardSwitcher keyboardSwitcher,
+ final Suggest suggest) {
assert latinIME != null;
- if (latinIME == null) {
- Log.w(TAG, "IMS is null; logging is off");
- } else {
- mFilesDir = latinIME.getFilesDir();
- if (mFilesDir == null || !mFilesDir.exists()) {
- Log.w(TAG, "IME storage directory does not exist.");
- }
- }
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(latinIME);
- if (prefs != null) {
- mUUIDString = getUUID(prefs);
- if (!prefs.contains(PREF_USABILITY_STUDY_MODE)) {
- Editor e = prefs.edit();
- e.putBoolean(PREF_USABILITY_STUDY_MODE, DEFAULT_USABILITY_STUDY_MODE);
- e.apply();
- }
- sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
- prefs.registerOnSharedPreferenceChangeListener(this);
-
- final long lastCleanupTime = prefs.getLong(PREF_LAST_CLEANUP_TIME, 0L);
- final long now = System.currentTimeMillis();
- if (lastCleanupTime + DURATION_BETWEEN_DIR_CLEANUP_IN_MS < now) {
- final long timeHorizon = now - MAX_LOGFILE_AGE_IN_MS;
- cleanupLoggingDir(mFilesDir, timeHorizon);
- Editor e = prefs.edit();
- e.putLong(PREF_LAST_CLEANUP_TIME, now);
- e.apply();
- }
+ mLatinIME = latinIME;
+ mFilesDir = latinIME.getFilesDir();
+ if (mFilesDir == null || !mFilesDir.exists()) {
+ Log.w(TAG, "IME storage directory does not exist. Cannot start logging.");
+ return;
}
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(latinIME);
+ mPrefs.registerOnSharedPreferenceChangeListener(this);
+
+ // Initialize fields from preferences
+ sIsLogging = ResearchSettings.readResearchLoggerEnabledFlag(mPrefs);
+
+ // Initialize fields from resources
final Resources res = latinIME.getResources();
sAccountType = res.getString(R.string.research_account_type);
sAllowedAccountDomain = res.getString(R.string.research_allowed_account_domain);
- mLatinIME = latinIME;
- mPrefs = prefs;
+
+ // Cleanup logging directory
+ // TODO: Move this and other file-related components to separate file.
+ final long lastCleanupTime = mPrefs.getLong(PREF_LAST_CLEANUP_TIME, 0L);
+ final long now = System.currentTimeMillis();
+ if (now - lastCleanupTime > DURATION_BETWEEN_DIR_CLEANUP_IN_MS) {
+ final long timeHorizon = now - MAX_LOGFILE_AGE_IN_MS;
+ cleanupLoggingDir(mFilesDir, timeHorizon);
+ mPrefs.edit().putLong(PREF_LAST_CLEANUP_TIME, now).apply();
+ }
+
+ // Initialize external services
mUploadIntent = new Intent(mLatinIME, UploaderService.class);
mUploadNowIntent = new Intent(mLatinIME, UploaderService.class);
mUploadNowIntent.putExtra(UploaderService.EXTRA_UPLOAD_UNCONDITIONALLY, true);
- mReplayer.setKeyboardSwitcher(keyboardSwitcher);
-
if (ProductionFlag.IS_EXPERIMENTAL) {
scheduleUploadingService(mLatinIME);
}
+ mReplayer.setKeyboardSwitcher(keyboardSwitcher);
}
/**
@@ -313,14 +312,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mMainKeyboardView = null;
}
- private boolean hasSeenSplash() {
- return mPrefs.getBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, false);
+ public void onDestroy() {
+ if (mPrefs != null) {
+ mPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
}
private Dialog mSplashDialog = null;
private void maybeShowSplashScreen() {
- if (hasSeenSplash()) {
+ if (ResearchSettings.readHasSeenSplash(mPrefs)) {
return;
}
if (mSplashDialog != null && mSplashDialog.isShowing()) {
@@ -373,32 +374,23 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
public void onUserLoggingConsent() {
- setLoggingAllowed(true);
if (mPrefs == null) {
- return;
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME);
+ if (mPrefs == null) return;
}
- final Editor e = mPrefs.edit();
- e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true);
- e.apply();
+ sIsLogging = true;
+ ResearchSettings.writeResearchLoggerEnabledFlag(mPrefs, true);
+ ResearchSettings.writeHasSeenSplash(mPrefs, true);
restart();
}
- private void setLoggingAllowed(boolean enableLogging) {
- if (mPrefs == null) {
- return;
- }
- Editor e = mPrefs.edit();
- e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging);
- e.apply();
- sIsLogging = enableLogging;
- }
-
private static int sLogFileCounter = 0;
private File createLogFile(final File filesDir) {
final StringBuilder sb = new StringBuilder();
sb.append(LOG_FILENAME_PREFIX).append('-');
- sb.append(mUUIDString).append('-');
+ final String uuid = ResearchSettings.readResearchLoggerUuid(mPrefs);
+ sb.append(uuid).append('-');
sb.append(TIMESTAMP_DATEFORMAT.format(new Date())).append('-');
// Sometimes logFiles are created within milliseconds of each other. Append a counter to
// separate these.
@@ -416,7 +408,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private File createUserRecordingFile(final File filesDir) {
final StringBuilder sb = new StringBuilder();
sb.append(USER_RECORDING_FILENAME_PREFIX).append('-');
- sb.append(mUUIDString).append('-');
+ final String uuid = ResearchSettings.readResearchLoggerUuid(mPrefs);
+ sb.append(uuid).append('-');
sb.append(TIMESTAMP_DATEFORMAT.format(new Date()));
sb.append(USER_RECORDING_FILENAME_SUFFIX);
return new File(filesDir, sb.toString());
@@ -458,17 +451,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// Log.w(TAG, "not in usability mode; not logging");
return;
}
- if (mFilesDir == null || !mFilesDir.exists()) {
- Log.w(TAG, "IME storage directory does not exist. Cannot start logging.");
- return;
- }
if (mMainLogBuffer == null) {
mMainResearchLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME);
- mMainLogBuffer = new MainLogBuffer() {
+ final int numWordsToIgnore = new Random().nextInt(NUMBER_OF_WORDS_BETWEEN_SAMPLES + 1);
+ mMainLogBuffer = new MainLogBuffer(NUMBER_OF_WORDS_BETWEEN_SAMPLES, numWordsToIgnore,
+ mSuggest) {
@Override
protected void publish(final ArrayList<LogUnit> logUnits,
boolean canIncludePrivateData) {
- canIncludePrivateData |= MainLogBuffer.IS_LOGGING_EVERYTHING;
+ canIncludePrivateData |= IS_LOGGING_EVERYTHING;
final int length = logUnits.size();
for (int i = 0; i < length; i++) {
final LogUnit logUnit = logUnits.get(i);
@@ -487,7 +478,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
}
};
- mMainLogBuffer.setSuggest(mSuggest);
}
if (mFeedbackLogBuffer == null) {
resetFeedbackLogging();
@@ -564,7 +554,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
@Override
- public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+ public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
if (key == null || prefs == null) {
return;
}
@@ -586,7 +576,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
presentFeedbackDialog(latinIME);
}
- public void presentFeedbackDialog(LatinIME latinIME) {
+ public void presentFeedbackDialog(final LatinIME latinIME) {
if (isMakingUserRecording()) {
saveRecording();
}
@@ -818,9 +808,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
if (mPrefs == null) {
return;
}
- final Editor e = mPrefs.edit();
- e.putString(PREF_RESEARCH_SAVED_CHANNEL, channelName);
- e.apply();
+ mPrefs.edit().putString(PREF_RESEARCH_SAVED_CHANNEL, channelName).apply();
}
}
@@ -835,10 +823,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mInFeedbackDialog = false;
}
- public void initSuggest(Suggest suggest) {
+ public void initSuggest(final Suggest suggest) {
mSuggest = suggest;
+ // MainLogBuffer has out-of-date Suggest object. Need to close it down and create a new
+ // one.
if (mMainLogBuffer != null) {
- mMainLogBuffer.setSuggest(mSuggest);
+ stop();
+ start();
}
}
@@ -1127,18 +1118,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
}
- private static String getUUID(final SharedPreferences prefs) {
- String uuidString = prefs.getString(PREF_RESEARCH_LOGGER_UUID_STRING, null);
- if (null == uuidString) {
- UUID uuid = UUID.randomUUID();
- uuidString = uuid.toString();
- Editor editor = prefs.edit();
- editor.putString(PREF_RESEARCH_LOGGER_UUID_STRING, uuidString);
- editor.apply();
- }
- return uuidString;
- }
-
private String scrubWord(String word) {
final Dictionary dictionary = getDictionary();
if (dictionary == null) {
@@ -1185,12 +1164,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
0);
final Integer versionCode = packageInfo.versionCode;
final String versionName = packageInfo.versionName;
+ final String uuid = ResearchSettings.readResearchLoggerUuid(researchLogger.mPrefs);
researchLogger.enqueueEvent(LOGSTATEMENT_LATIN_IME_ON_START_INPUT_VIEW_INTERNAL,
- researchLogger.mUUIDString, editorInfo.packageName,
- Integer.toHexString(editorInfo.inputType),
+ uuid, editorInfo.packageName, Integer.toHexString(editorInfo.inputType),
Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId,
Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName,
- OUTPUT_FORMAT_VERSION, MainLogBuffer.IS_LOGGING_EVERYTHING,
+ OUTPUT_FORMAT_VERSION, IS_LOGGING_EVERYTHING,
ProductionFlag.IS_EXPERIMENTAL_DEBUG);
} catch (NameNotFoundException e) {
e.printStackTrace();
@@ -1226,17 +1205,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action,
final long eventTime, final int index, final int id, final int x, final int y) {
if (me != null) {
- final String actionString;
- switch (action) {
- case MotionEvent.ACTION_CANCEL: actionString = "CANCEL"; break;
- case MotionEvent.ACTION_UP: actionString = "UP"; break;
- case MotionEvent.ACTION_DOWN: actionString = "DOWN"; break;
- case MotionEvent.ACTION_POINTER_UP: actionString = "POINTER_UP"; break;
- case MotionEvent.ACTION_POINTER_DOWN: actionString = "POINTER_DOWN"; break;
- case MotionEvent.ACTION_MOVE: actionString = "MOVE"; break;
- case MotionEvent.ACTION_OUTSIDE: actionString = "OUTSIDE"; break;
- default: actionString = "ACTION_" + action; break;
- }
+ final String actionString = LoggingUtils.getMotionEventActionTypeString(action);
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT,
actionString, false /* IS_LOGGING_RELATED */, MotionEvent.obtain(me));
diff --git a/java/src/com/android/inputmethod/research/ResearchSettings.java b/java/src/com/android/inputmethod/research/ResearchSettings.java
new file mode 100644
index 000000000..11e9ac77a
--- /dev/null
+++ b/java/src/com/android/inputmethod/research/ResearchSettings.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.research;
+
+import android.content.SharedPreferences;
+
+import java.util.UUID;
+
+public final class ResearchSettings {
+ public static final String PREF_RESEARCH_LOGGER_UUID = "pref_research_logger_uuid";
+ public static final String PREF_RESEARCH_LOGGER_ENABLED_FLAG =
+ "pref_research_logger_enabled_flag";
+ public static final String PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH =
+ "pref_research_logger_has_seen_splash";
+
+ private ResearchSettings() {
+ // Intentional empty constructor for singleton.
+ }
+
+ public static String readResearchLoggerUuid(final SharedPreferences prefs) {
+ if (prefs.contains(PREF_RESEARCH_LOGGER_UUID)) {
+ return prefs.getString(PREF_RESEARCH_LOGGER_UUID, null);
+ }
+ // Generate a random string as uuid if not yet set
+ final String newUuid = UUID.randomUUID().toString();
+ prefs.edit().putString(PREF_RESEARCH_LOGGER_UUID, newUuid).apply();
+ return newUuid;
+ }
+
+ public static boolean readResearchLoggerEnabledFlag(final SharedPreferences prefs) {
+ return prefs.getBoolean(PREF_RESEARCH_LOGGER_ENABLED_FLAG, false);
+ }
+
+ public static void writeResearchLoggerEnabledFlag(final SharedPreferences prefs,
+ final boolean isEnabled) {
+ prefs.edit().putBoolean(PREF_RESEARCH_LOGGER_ENABLED_FLAG, isEnabled).apply();
+ }
+
+ public static boolean readHasSeenSplash(final SharedPreferences prefs) {
+ return prefs.getBoolean(PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH, false);
+ }
+
+ public static void writeHasSeenSplash(final SharedPreferences prefs,
+ final boolean hasSeenSplash) {
+ prefs.edit().putBoolean(PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH, hasSeenSplash).apply();
+ }
+}
diff --git a/java/src/com/android/inputmethod/research/Uploader.java b/java/src/com/android/inputmethod/research/Uploader.java
new file mode 100644
index 000000000..df495a88d
--- /dev/null
+++ b/java/src/com/android/inputmethod/research/Uploader.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.research;
+
+import android.Manifest;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.BatteryManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.define.ProductionFlag;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Manages the uploading of ResearchLog files.
+ */
+public final class Uploader {
+ private static final String TAG = Uploader.class.getSimpleName();
+ private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
+ // Set IS_INHIBITING_AUTO_UPLOAD to true for local testing
+ private static final boolean IS_INHIBITING_AUTO_UPLOAD = false
+ && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Force false for non-debug builds
+ private static final int BUF_SIZE = 1024 * 8;
+
+ private final Context mContext;
+ private final File mFilesDir;
+ private final URL mUrl;
+
+ public Uploader(final Context context) {
+ mContext = context;
+ mFilesDir = context.getFilesDir();
+
+ final String urlString = context.getString(R.string.research_logger_upload_url);
+ if (TextUtils.isEmpty(urlString)) {
+ mUrl = null;
+ return;
+ }
+ URL url = null;
+ try {
+ url = new URL(urlString);
+ } catch (final MalformedURLException e) {
+ Log.e(TAG, "Bad URL for uploading", e);
+ }
+ mUrl = url;
+ }
+
+ public boolean isPossibleToUpload() {
+ return hasUploadingPermission() && mUrl != null && !IS_INHIBITING_AUTO_UPLOAD;
+ }
+
+ private boolean hasUploadingPermission() {
+ final PackageManager packageManager = mContext.getPackageManager();
+ return packageManager.checkPermission(Manifest.permission.INTERNET,
+ mContext.getPackageName()) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ public boolean isConvenientToUpload() {
+ return isExternallyPowered() && hasWifiConnection();
+ }
+
+ private boolean isExternallyPowered() {
+ final Intent intent = mContext.registerReceiver(null, new IntentFilter(
+ Intent.ACTION_BATTERY_CHANGED));
+ final int pluggedState = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ return pluggedState == BatteryManager.BATTERY_PLUGGED_AC
+ || pluggedState == BatteryManager.BATTERY_PLUGGED_USB;
+ }
+
+ private boolean hasWifiConnection() {
+ final ConnectivityManager manager =
+ (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ return wifiInfo.isConnected();
+ }
+
+ public void doUpload() {
+ if (mFilesDir == null) {
+ return;
+ }
+ final File[] files = mFilesDir.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(final File pathname) {
+ return pathname.getName().startsWith(ResearchLogger.LOG_FILENAME_PREFIX)
+ && !pathname.canWrite();
+ }
+ });
+ for (final File file : files) {
+ uploadFile(file);
+ }
+ }
+
+ private void uploadFile(final File file) {
+ if (DEBUG) {
+ Log.d(TAG, "attempting upload of " + file.getAbsolutePath());
+ }
+ final int contentLength = (int) file.length();
+ HttpURLConnection connection = null;
+ InputStream fileInputStream = null;
+ try {
+ fileInputStream = new FileInputStream(file);
+ connection = (HttpURLConnection) mUrl.openConnection();
+ connection.setRequestMethod("PUT");
+ connection.setDoOutput(true);
+ connection.setFixedLengthStreamingMode(contentLength);
+ final OutputStream outputStream = connection.getOutputStream();
+ uploadContents(fileInputStream, outputStream);
+ if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ Log.d(TAG, "upload failed: " + connection.getResponseCode());
+ final InputStream netInputStream = connection.getInputStream();
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(
+ netInputStream));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ Log.d(TAG, "| " + reader.readLine());
+ }
+ reader.close();
+ return;
+ }
+ file.delete();
+ if (DEBUG) {
+ Log.d(TAG, "upload successful");
+ }
+ } catch (final IOException e) {
+ Log.e(TAG, "Exception uploading file", e);
+ } finally {
+ if (fileInputStream != null) {
+ try {
+ fileInputStream.close();
+ } catch (final IOException e) {
+ Log.e(TAG, "Exception closing uploaded file", e);
+ }
+ }
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ }
+
+ private static void uploadContents(final InputStream is, final OutputStream os)
+ throws IOException {
+ // TODO: Switch to NIO.
+ final byte[] buf = new byte[BUF_SIZE];
+ int numBytesRead;
+ while ((numBytesRead = is.read(buf)) != -1) {
+ os.write(buf, 0, numBytesRead);
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/research/UploaderService.java b/java/src/com/android/inputmethod/research/UploaderService.java
index 89c67fbb2..26b651056 100644
--- a/java/src/com/android/inputmethod/research/UploaderService.java
+++ b/java/src/com/android/inputmethod/research/UploaderService.java
@@ -16,189 +16,44 @@
package com.android.inputmethod.research;
-import android.Manifest;
import android.app.AlarmManager;
import android.app.IntentService;
-import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.BatteryManager;
import android.os.Bundle;
-import android.util.Log;
-import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.define.ProductionFlag;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-
+/**
+ * Service to invoke the uploader.
+ *
+ * Can be regularly invoked, invoked on boot, etc.
+ */
public final class UploaderService extends IntentService {
private static final String TAG = UploaderService.class.getSimpleName();
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
- // Set IS_INHIBITING_AUTO_UPLOAD to true for local testing
- private static final boolean IS_INHIBITING_AUTO_UPLOAD = false
- && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Force false in production
public static final long RUN_INTERVAL = AlarmManager.INTERVAL_HOUR;
public static final String EXTRA_UPLOAD_UNCONDITIONALLY = UploaderService.class.getName()
+ ".extra.UPLOAD_UNCONDITIONALLY";
- private static final int BUF_SIZE = 1024 * 8;
protected static final int TIMEOUT_IN_MS = 1000 * 4;
- private boolean mCanUpload;
- private File mFilesDir;
- private URL mUrl;
-
public UploaderService() {
super("Research Uploader Service");
}
@Override
- public void onCreate() {
- super.onCreate();
-
- mCanUpload = false;
- mFilesDir = null;
- mUrl = null;
-
- final PackageManager packageManager = getPackageManager();
- final boolean hasPermission = packageManager.checkPermission(Manifest.permission.INTERNET,
- getPackageName()) == PackageManager.PERMISSION_GRANTED;
- if (!hasPermission) {
- return;
- }
-
- try {
- final String urlString = getString(R.string.research_logger_upload_url);
- if (urlString == null || urlString.equals("")) {
- return;
- }
- mFilesDir = getFilesDir();
- mUrl = new URL(urlString);
- mCanUpload = true;
- } catch (MalformedURLException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {
- if (!mCanUpload) {
- return;
- }
- boolean isUploadingUnconditionally = false;
- Bundle bundle = intent.getExtras();
- if (bundle != null && bundle.containsKey(EXTRA_UPLOAD_UNCONDITIONALLY)) {
- isUploadingUnconditionally = bundle.getBoolean(EXTRA_UPLOAD_UNCONDITIONALLY);
- }
- doUpload(isUploadingUnconditionally);
- }
-
- private boolean isExternallyPowered() {
- final Intent intent = registerReceiver(null, new IntentFilter(
- Intent.ACTION_BATTERY_CHANGED));
- final int pluggedState = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
- return pluggedState == BatteryManager.BATTERY_PLUGGED_AC
- || pluggedState == BatteryManager.BATTERY_PLUGGED_USB;
- }
-
- private boolean hasWifiConnection() {
- final ConnectivityManager manager =
- (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
- final NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- return wifiInfo.isConnected();
- }
-
- private void doUpload(final boolean isUploadingUnconditionally) {
- if (!isUploadingUnconditionally && (!isExternallyPowered() || !hasWifiConnection()
- || IS_INHIBITING_AUTO_UPLOAD)) {
- return;
- }
- if (mFilesDir == null) {
- return;
- }
- final File[] files = mFilesDir.listFiles(new FileFilter() {
- @Override
- public boolean accept(File pathname) {
- return pathname.getName().startsWith(ResearchLogger.LOG_FILENAME_PREFIX)
- && !pathname.canWrite();
- }
- });
- boolean success = true;
- if (files.length == 0) {
- success = false;
- }
- for (final File file : files) {
- if (!uploadFile(file)) {
- success = false;
- }
+ protected void onHandleIntent(final Intent intent) {
+ final Uploader uploader = new Uploader(this);
+ if (!uploader.isPossibleToUpload()) return;
+ if (isUploadingUnconditionally(intent.getExtras()) || uploader.isConvenientToUpload()) {
+ uploader.doUpload();
}
}
- private boolean uploadFile(File file) {
- if (DEBUG) {
- Log.d(TAG, "attempting upload of " + file.getAbsolutePath());
- }
- boolean success = false;
- final int contentLength = (int) file.length();
- HttpURLConnection connection = null;
- InputStream fileInputStream = null;
- try {
- fileInputStream = new FileInputStream(file);
- connection = (HttpURLConnection) mUrl.openConnection();
- connection.setRequestMethod("PUT");
- connection.setDoOutput(true);
- connection.setFixedLengthStreamingMode(contentLength);
- final OutputStream os = connection.getOutputStream();
- final byte[] buf = new byte[BUF_SIZE];
- int numBytesRead;
- while ((numBytesRead = fileInputStream.read(buf)) != -1) {
- os.write(buf, 0, numBytesRead);
- if (DEBUG) {
- Log.d(TAG, new String(buf));
- }
- }
- if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
- Log.d(TAG, "upload failed: " + connection.getResponseCode());
- InputStream netInputStream = connection.getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(netInputStream));
- String line;
- while ((line = reader.readLine()) != null) {
- Log.d(TAG, "| " + reader.readLine());
- }
- reader.close();
- return success;
- }
- file.delete();
- success = true;
- if (DEBUG) {
- Log.d(TAG, "upload successful");
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (fileInputStream != null) {
- try {
- fileInputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (connection != null) {
- connection.disconnect();
- }
+ private boolean isUploadingUnconditionally(final Bundle bundle) {
+ if (bundle == null) return false;
+ if (bundle.containsKey(EXTRA_UPLOAD_UNCONDITIONALLY)) {
+ return bundle.getBoolean(EXTRA_UPLOAD_UNCONDITIONALLY);
}
- return success;
+ return false;
}
}