aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xAndroid.mk9
-rwxr-xr-xAndroidManifest.xml14
-rw-r--r--dictionary/jni/com_android_inputmethod_latin_BinaryDictionary.cpp10
-rw-r--r--dictionary/src/dictionary.cpp11
-rw-r--r--dictionary/src/dictionary.h1
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/btn_keyboard_key_normal.9.pngbin696 -> 715 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/btn_keyboard_key_normal_off.9.pngbin941 -> 1001 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/btn_keyboard_key_normal_on.9.pngbin1076 -> 1077 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/btn_keyboard_key_pressed.9.pngbin696 -> 745 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/btn_keyboard_key_pressed_off.9.pngbin964 -> 1042 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/btn_keyboard_key_pressed_on.9.pngbin1055 -> 1105 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/highlight_pressed.pngbin1527 -> 4110 bytes
-rw-r--r--res/drawable-hdpi/ic_mic_dialog.pngbin0 -> 3634 bytes
-rw-r--r--res/drawable-hdpi/ic_suggest_strip_microphone.pngbin0 -> 548 bytes
-rw-r--r--res/drawable-hdpi/ic_suggest_strip_microphone_swipe.pngbin0 -> 438 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/keyboard_suggest_strip_divider.pngbin172 -> 2852 bytes
-rw-r--r--res/drawable-hdpi/list_selector_background_pressed.9.pngbin0 -> 4203 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-hdpi/mic_slash.pngbin3095 -> 5615 bytes
-rwxr-xr-xres/drawable-hdpi/speak_now_level0.pngbin1508 -> 1512 bytes
-rwxr-xr-xres/drawable-hdpi/speak_now_level1.pngbin1587 -> 2215 bytes
-rwxr-xr-xres/drawable-hdpi/speak_now_level2.pngbin1687 -> 3130 bytes
-rwxr-xr-xres/drawable-hdpi/speak_now_level3.pngbin1636 -> 3647 bytes
-rwxr-xr-xres/drawable-hdpi/speak_now_level4.pngbin1635 -> 3626 bytes
-rwxr-xr-xres/drawable-hdpi/speak_now_level5.pngbin1706 -> 3670 bytes
-rwxr-xr-xres/drawable-hdpi/speak_now_level6.pngbin0 -> 4006 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_123_mic.pngbin0 -> 2575 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_feedback_123_mic.pngbin0 -> 1046 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.pngbin0 -> 322 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.pngbin0 -> 328 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_feedback_mic.pngbin0 -> 681 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_feedback_tab.pngbin0 -> 462 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_feedback_tabprev.pngbin0 -> 463 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_globe.pngbin0 -> 2093 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_language_arrows_left.pngbin0 -> 314 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_language_arrows_right.pngbin0 -> 316 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_mic.pngbin0 -> 1440 bytes
-rwxr-xr-xres/drawable-hdpi/sym_keyboard_num7.pngbin3664 -> 3684 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_tab.pngbin0 -> 1027 bytes
-rw-r--r--res/drawable-hdpi/sym_keyboard_tabprev.pngbin0 -> 1033 bytes
-rwxr-xr-xres/drawable-hdpi/voice_ime_background.9.png (renamed from res/drawable-hdpi/voice_background.9.png)bin2349 -> 2349 bytes
-rw-r--r--res/drawable-mdpi/btn_keyboard_key_normal.9.pngbin809 -> 726 bytes
-rw-r--r--[-rwxr-xr-x]res/drawable-mdpi/btn_keyboard_key_pressed.9.pngbin736 -> 664 bytes
-rw-r--r--res/drawable-mdpi/ic_mic_dialog.pngbin0 -> 3312 bytes
-rw-r--r--res/drawable-mdpi/ic_suggest_strip_microphone.pngbin0 -> 398 bytes
-rw-r--r--res/drawable-mdpi/ic_suggest_strip_microphone_swipe.pngbin0 -> 309 bytes
-rw-r--r--res/drawable-mdpi/list_selector_background_pressed.9.pngbin0 -> 11006 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_123_mic.pngbin0 -> 1540 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_feedback_123_mic.pngbin0 -> 694 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_feedback_language_arrows_left.pngbin0 -> 249 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_feedback_language_arrows_right.pngbin0 -> 249 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_feedback_mic.pngbin0 -> 483 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_feedback_tab.pngbin0 -> 364 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_feedback_tabprev.pngbin0 -> 365 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_globe.pngbin0 -> 1290 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_language_arrows_left.pngbin0 -> 261 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_language_arrows_right.pngbin0 -> 257 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_mic.pngbin0 -> 859 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_num7.pngbin1997 -> 2051 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_tab.pngbin0 -> 645 bytes
-rw-r--r--res/drawable-mdpi/sym_keyboard_tabprev.pngbin0 -> 612 bytes
-rw-r--r--res/drawable/cancel.pngbin0 -> 1259 bytes
-rw-r--r--res/drawable/caution.pngbin0 -> 1100 bytes
-rw-r--r--res/drawable/dialog_top_dark_bottom_medium.9.pngbin0 -> 1574 bytes
-rw-r--r--res/drawable/ic_dialog_alert_large.pngbin0 -> 4089 bytes
-rw-r--r--res/drawable/ic_dialog_voice_input.pngbin0 -> 1040 bytes
-rw-r--r--res/drawable/ic_dialog_wave_0_0.pngbin0 -> 8471 bytes
-rw-r--r--res/drawable/ic_dialog_wave_1_3.pngbin0 -> 9017 bytes
-rw-r--r--res/drawable/ic_dialog_wave_2_3.pngbin0 -> 9614 bytes
-rw-r--r--res/drawable/ic_dialog_wave_3_3.pngbin0 -> 10089 bytes
-rw-r--r--res/drawable/ic_dialog_wave_4_3.pngbin0 -> 10514 bytes
-rw-r--r--res/drawable/mic_slash.pngbin0 -> 3098 bytes
-rw-r--r--res/drawable/ok_cancel.pngbin0 -> 8453 bytes
-rw-r--r--res/drawable/speak_now_level0.pngbin0 -> 3263 bytes
-rw-r--r--res/drawable/speak_now_level1.pngbin0 -> 3572 bytes
-rw-r--r--res/drawable/speak_now_level2.pngbin0 -> 3974 bytes
-rw-r--r--res/drawable/speak_now_level3.pngbin0 -> 4270 bytes
-rw-r--r--res/drawable/speak_now_level4.pngbin0 -> 4241 bytes
-rw-r--r--res/drawable/speak_now_level5.pngbin0 -> 4252 bytes
-rw-r--r--res/drawable/speak_now_level6.pngbin0 -> 2201 bytes
-rw-r--r--res/drawable/voice_ime_background.9.pngbin0 -> 20661 bytes
-rw-r--r--res/drawable/voice_swipe_hint.pngbin0 -> 3111 bytes
-rw-r--r--res/drawable/working.pngbin0 -> 33111 bytes
-rwxr-xr-xres/layout/candidates.xml18
-rwxr-xr-xres/layout/input.xml2
-rw-r--r--res/layout/recognition_status.xml98
-rw-r--r--res/layout/voice_punctuation_hint.xml49
-rw-r--r--res/layout/voice_swipe_hint.xml56
-rw-r--r--res/values-cs/strings.xml34
-rw-r--r--res/values-da/strings.xml34
-rw-r--r--res/values-de/strings.xml34
-rw-r--r--res/values-el/strings.xml34
-rw-r--r--res/values-es-rUS/strings.xml34
-rw-r--r--res/values-es/strings.xml34
-rw-r--r--res/values-fr-rCA/strings.xml19
-rw-r--r--res/values-fr/strings.xml34
-rw-r--r--res/values-it/strings.xml34
-rw-r--r--res/values-ja/strings.xml34
-rw-r--r--res/values-ko/strings.xml34
-rw-r--r--res/values-nb/strings.xml34
-rw-r--r--res/values-nl/strings.xml34
-rw-r--r--res/values-pl/strings.xml34
-rw-r--r--res/values-pt-rPT/strings.xml34
-rw-r--r--res/values-pt/strings.xml34
-rw-r--r--res/values-ru/strings.xml34
-rw-r--r--res/values-sv/strings.xml34
-rw-r--r--res/values-tr/donottranslate.xml2
-rw-r--r--res/values-tr/strings.xml34
-rw-r--r--res/values-zh-rCN/strings.xml49
-rw-r--r--res/values-zh-rTW/strings.xml34
-rw-r--r--res/values/bools.xml2
-rw-r--r--res/values/donottranslate.xml6
-rw-r--r--res/values/keycodes.xml24
-rw-r--r--res/values/strings.xml106
-rwxr-xr-xres/xml-de/kbd_qwerty.xml53
-rw-r--r--res/xml-fr/kbd_qwerty.xml75
-rwxr-xr-xres/xml-ru/kbd_qwerty.xml174
-rwxr-xr-xres/xml/kbd_extension.xml61
-rwxr-xr-xres/xml/kbd_qwerty.xml65
-rwxr-xr-xres/xml/kbd_symbols.xml16
-rwxr-xr-xres/xml/kbd_symbols_shift.xml15
-rw-r--r--res/xml/language_prefs.xml19
-rw-r--r--res/xml/method.xml2
-rw-r--r--res/xml/prefs.xml24
-rw-r--r--src/com/android/inputmethod/latin/BinaryDictionary.java11
-rwxr-xr-xsrc/com/android/inputmethod/latin/CandidateView.java76
-rw-r--r--src/com/android/inputmethod/latin/Dictionary.java5
-rw-r--r--src/com/android/inputmethod/latin/ExpandableDictionary.java4
-rw-r--r--src/com/android/inputmethod/latin/Hints.java188
-rw-r--r--src/com/android/inputmethod/latin/InputLanguageSelection.java178
-rw-r--r--src/com/android/inputmethod/latin/KeyboardSwitcher.java156
-rw-r--r--src/com/android/inputmethod/latin/LanguageSwitcher.java172
-rw-r--r--src/com/android/inputmethod/latin/LatinIME.java956
-rw-r--r--src/com/android/inputmethod/latin/LatinIMEBackupAgent.java2
-rw-r--r--src/com/android/inputmethod/latin/LatinIMESettings.java149
-rw-r--r--src/com/android/inputmethod/latin/LatinKeyboard.java423
-rw-r--r--src/com/android/inputmethod/latin/LatinKeyboardView.java139
-rwxr-xr-xsrc/com/android/inputmethod/latin/Suggest.java31
-rw-r--r--src/com/android/inputmethod/latin/TextEntryState.java1
-rw-r--r--src/com/android/inputmethod/latin/WordComposer.java19
-rw-r--r--src/com/android/inputmethod/voice/EditingUtil.java162
-rw-r--r--src/com/android/inputmethod/voice/FieldContext.java102
-rw-r--r--src/com/android/inputmethod/voice/LatinIMEWithVoice.java28
-rw-r--r--src/com/android/inputmethod/voice/LatinIMEWithVoiceSettings.java21
-rw-r--r--src/com/android/inputmethod/voice/RecognitionView.java321
-rw-r--r--src/com/android/inputmethod/voice/SettingsUtil.java113
-rw-r--r--src/com/android/inputmethod/voice/VoiceInput.java500
-rw-r--r--src/com/android/inputmethod/voice/VoiceInputLogger.java177
-rw-r--r--src/com/android/inputmethod/voice/WaveformImage.java90
-rw-r--r--src/com/android/inputmethod/voice/Whitelist.java67
-rw-r--r--src/com/google/android/voicesearch/LatinIMEWithVoice.java29
-rw-r--r--src/com/google/android/voicesearch/LatinIMEWithVoiceSettings.java5
151 files changed, 5263 insertions, 488 deletions
diff --git a/Android.mk b/Android.mk
index e3215e822..5614e8f03 100755
--- a/Android.mk
+++ b/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
@@ -11,7 +11,12 @@ LOCAL_CERTIFICATE := shared
LOCAL_JNI_SHARED_LIBRARIES := libjni_latinime
-LOCAL_AAPT_FLAGS := -0 .dict
+LOCAL_STATIC_JAVA_LIBRARIES := android-common
+#LOCAL_AAPT_FLAGS := -0 .dict
+
+#LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := google-common android-common
include $(BUILD_PACKAGE)
include $(LOCAL_PATH)/dictionary/Android.mk
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 697dce28a..2d152ad10 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,10 +1,11 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.inputmethod.latin"
android:sharedUserId="android.uid.shared">
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
<uses-permission android:name="android.permission.BACKUP_DATA" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
<application android:label="@string/english_ime_name"
android:backupAgent="LatinIMEBackupAgent"
@@ -18,11 +19,18 @@
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
-
+
<activity android:name="LatinIMESettings" android:label="@string/english_ime_settings">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
- </activity>
+ </activity>
+
+ <activity android:name="InputLanguageSelection"
+ android:label="@string/language_selection_title">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/dictionary/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/dictionary/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index c9e158c4c..3076085e4 100644
--- a/dictionary/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/dictionary/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -38,6 +38,7 @@ using namespace android;
static jfieldID sDescriptorField;
static jfieldID sAssetManagerNativeField;
static jmethodID sAddWordMethod;
+static jfieldID sDictLength;
//
// helper function to throw an exception
@@ -79,6 +80,7 @@ static jint latinime_BinaryDictionary_open
}
Dictionary *dictionary = new Dictionary(dict, typedLetterMultiplier, fullWordMultiplier);
dictionary->setAsset(dictAsset);
+ env->SetIntField(object, sDictLength, (jint) dictAsset->getLength());
env->ReleaseStringUTFChars(resourceString, resourcePath);
return (jint) dictionary;
@@ -176,6 +178,14 @@ static int registerNatives(JNIEnv *env)
}
sAssetManagerNativeField = env->GetFieldID(clazz, "mObject", "I");
+ // Get the field pointer for the dictionary length
+ clazz = env->FindClass(kClassPathName);
+ if (clazz == NULL) {
+ LOGE("Can't find %s", kClassPathName);
+ return -1;
+ }
+ sDictLength = env->GetFieldID(clazz, "mDictLength", "I");
+
return registerNativeMethods(env,
kClassPathName, gMethods, sizeof(gMethods) / sizeof(gMethods[0]));
}
diff --git a/dictionary/src/dictionary.cpp b/dictionary/src/dictionary.cpp
index cc711f419..306aff527 100644
--- a/dictionary/src/dictionary.cpp
+++ b/dictionary/src/dictionary.cpp
@@ -51,6 +51,7 @@ Dictionary::~Dictionary()
int Dictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
int maxWordLength, int maxWords, int maxAlternatives, int skipPos)
{
+ int suggWords;
mFrequencies = frequencies;
mOutputChars = outWords;
mInputCodes = codes;
@@ -58,14 +59,16 @@ int Dictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWor
mMaxAlternatives = maxAlternatives;
mMaxWordLength = maxWordLength;
mMaxWords = maxWords;
- mWords = 0;
mSkipPos = skipPos;
mMaxEditDistance = mInputLength < 5 ? 2 : mInputLength / 2;
getWordsRec(0, 0, mInputLength * 3, false, 1, 0, 0);
- if (DEBUG_DICT) LOGI("Returning %d words", mWords);
- return mWords;
+ // Get the word count
+ suggWords = 0;
+ while (suggWords < mMaxWords && mFrequencies[suggWords] > 0) suggWords++;
+ if (DEBUG_DICT) LOGI("Returning %d words", suggWords);
+ return suggWords;
}
unsigned short
@@ -138,8 +141,6 @@ Dictionary::addWord(unsigned short *word, int length, int frequency)
*dest++ = *word++;
}
*dest = 0; // NULL terminate
- // Update the word count
- if (insertAt + 1 > mWords) mWords = insertAt + 1;
if (DEBUG_DICT) LOGI("Added word at %d\n", insertAt);
return true;
}
diff --git a/dictionary/src/dictionary.h b/dictionary/src/dictionary.h
index 8f195ca9a..a12c035c8 100644
--- a/dictionary/src/dictionary.h
+++ b/dictionary/src/dictionary.h
@@ -60,7 +60,6 @@ private:
int *mFrequencies;
int mMaxWords;
int mMaxWordLength;
- int mWords;
unsigned short *mOutputChars;
int *mInputCodes;
int mInputLength;
diff --git a/res/drawable-hdpi/btn_keyboard_key_normal.9.png b/res/drawable-hdpi/btn_keyboard_key_normal.9.png
index 90b51fa63..42c7c146d 100755..100644
--- a/res/drawable-hdpi/btn_keyboard_key_normal.9.png
+++ b/res/drawable-hdpi/btn_keyboard_key_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png b/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png
index 6ddd516e7..01e2506b0 100755..100644
--- a/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png
+++ b/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png b/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png
index 65fdeb353..83c6eb3fc 100755..100644
--- a/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png
+++ b/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_keyboard_key_pressed.9.png b/res/drawable-hdpi/btn_keyboard_key_pressed.9.png
index efaad9612..e047eaff1 100755..100644
--- a/res/drawable-hdpi/btn_keyboard_key_pressed.9.png
+++ b/res/drawable-hdpi/btn_keyboard_key_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png b/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png
index 439271723..218a2d29e 100755..100644
--- a/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png
+++ b/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png b/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png
index c2cc32044..afe49512e 100755..100644
--- a/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png
+++ b/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png
Binary files differ
diff --git a/res/drawable-hdpi/highlight_pressed.png b/res/drawable-hdpi/highlight_pressed.png
index d2276feb8..ae04901a0 100755..100644
--- a/res/drawable-hdpi/highlight_pressed.png
+++ b/res/drawable-hdpi/highlight_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_mic_dialog.png b/res/drawable-hdpi/ic_mic_dialog.png
new file mode 100644
index 000000000..349dc4b37
--- /dev/null
+++ b/res/drawable-hdpi/ic_mic_dialog.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_suggest_strip_microphone.png b/res/drawable-hdpi/ic_suggest_strip_microphone.png
new file mode 100644
index 000000000..c00b4aaa6
--- /dev/null
+++ b/res/drawable-hdpi/ic_suggest_strip_microphone.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_suggest_strip_microphone_swipe.png b/res/drawable-hdpi/ic_suggest_strip_microphone_swipe.png
new file mode 100644
index 000000000..256dc3d61
--- /dev/null
+++ b/res/drawable-hdpi/ic_suggest_strip_microphone_swipe.png
Binary files differ
diff --git a/res/drawable-hdpi/keyboard_suggest_strip_divider.png b/res/drawable-hdpi/keyboard_suggest_strip_divider.png
index 1a03c52e6..a5980388a 100755..100644
--- a/res/drawable-hdpi/keyboard_suggest_strip_divider.png
+++ b/res/drawable-hdpi/keyboard_suggest_strip_divider.png
Binary files differ
diff --git a/res/drawable-hdpi/list_selector_background_pressed.9.png b/res/drawable-hdpi/list_selector_background_pressed.9.png
new file mode 100644
index 000000000..ba79cf7f8
--- /dev/null
+++ b/res/drawable-hdpi/list_selector_background_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/mic_slash.png b/res/drawable-hdpi/mic_slash.png
index 87153dc33..a7b734c71 100755..100644
--- a/res/drawable-hdpi/mic_slash.png
+++ b/res/drawable-hdpi/mic_slash.png
Binary files differ
diff --git a/res/drawable-hdpi/speak_now_level0.png b/res/drawable-hdpi/speak_now_level0.png
index 5c5ca309d..a681da606 100755
--- a/res/drawable-hdpi/speak_now_level0.png
+++ b/res/drawable-hdpi/speak_now_level0.png
Binary files differ
diff --git a/res/drawable-hdpi/speak_now_level1.png b/res/drawable-hdpi/speak_now_level1.png
index 4d5f7d6bb..0dbec69a7 100755
--- a/res/drawable-hdpi/speak_now_level1.png
+++ b/res/drawable-hdpi/speak_now_level1.png
Binary files differ
diff --git a/res/drawable-hdpi/speak_now_level2.png b/res/drawable-hdpi/speak_now_level2.png
index be5a7d37a..45cbff2b7 100755
--- a/res/drawable-hdpi/speak_now_level2.png
+++ b/res/drawable-hdpi/speak_now_level2.png
Binary files differ
diff --git a/res/drawable-hdpi/speak_now_level3.png b/res/drawable-hdpi/speak_now_level3.png
index 82968f476..abda8f683 100755
--- a/res/drawable-hdpi/speak_now_level3.png
+++ b/res/drawable-hdpi/speak_now_level3.png
Binary files differ
diff --git a/res/drawable-hdpi/speak_now_level4.png b/res/drawable-hdpi/speak_now_level4.png
index e8ce7bd7f..18356351a 100755
--- a/res/drawable-hdpi/speak_now_level4.png
+++ b/res/drawable-hdpi/speak_now_level4.png
Binary files differ
diff --git a/res/drawable-hdpi/speak_now_level5.png b/res/drawable-hdpi/speak_now_level5.png
index 77d0b8e9b..7d4fd5f20 100755
--- a/res/drawable-hdpi/speak_now_level5.png
+++ b/res/drawable-hdpi/speak_now_level5.png
Binary files differ
diff --git a/res/drawable-hdpi/speak_now_level6.png b/res/drawable-hdpi/speak_now_level6.png
new file mode 100755
index 000000000..e06990faa
--- /dev/null
+++ b/res/drawable-hdpi/speak_now_level6.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_123_mic.png b/res/drawable-hdpi/sym_keyboard_123_mic.png
new file mode 100644
index 000000000..62669803d
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_123_mic.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png b/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png
new file mode 100644
index 000000000..f57e581d5
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png b/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png
new file mode 100644
index 000000000..c7638bff1
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png b/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png
new file mode 100644
index 000000000..7acb07c86
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_feedback_mic.png b/res/drawable-hdpi/sym_keyboard_feedback_mic.png
new file mode 100644
index 000000000..cb86a5598
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_feedback_mic.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_feedback_tab.png b/res/drawable-hdpi/sym_keyboard_feedback_tab.png
new file mode 100644
index 000000000..7754752f3
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_feedback_tab.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_feedback_tabprev.png b/res/drawable-hdpi/sym_keyboard_feedback_tabprev.png
new file mode 100644
index 000000000..36f6b5364
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_feedback_tabprev.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_globe.png b/res/drawable-hdpi/sym_keyboard_globe.png
new file mode 100644
index 000000000..fa747642d
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_globe.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_language_arrows_left.png b/res/drawable-hdpi/sym_keyboard_language_arrows_left.png
new file mode 100644
index 000000000..65ccfda87
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_language_arrows_left.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_language_arrows_right.png b/res/drawable-hdpi/sym_keyboard_language_arrows_right.png
new file mode 100644
index 000000000..0d01bc224
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_language_arrows_right.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_mic.png b/res/drawable-hdpi/sym_keyboard_mic.png
new file mode 100644
index 000000000..0a0a68a96
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_mic.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_num7.png b/res/drawable-hdpi/sym_keyboard_num7.png
index 2246972a8..14931c18c 100755
--- a/res/drawable-hdpi/sym_keyboard_num7.png
+++ b/res/drawable-hdpi/sym_keyboard_num7.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_tab.png b/res/drawable-hdpi/sym_keyboard_tab.png
new file mode 100644
index 000000000..1d4d92bd1
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_tab.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_keyboard_tabprev.png b/res/drawable-hdpi/sym_keyboard_tabprev.png
new file mode 100644
index 000000000..51bff1bcd
--- /dev/null
+++ b/res/drawable-hdpi/sym_keyboard_tabprev.png
Binary files differ
diff --git a/res/drawable-hdpi/voice_background.9.png b/res/drawable-hdpi/voice_ime_background.9.png
index 73fb0901e..73fb0901e 100755
--- a/res/drawable-hdpi/voice_background.9.png
+++ b/res/drawable-hdpi/voice_ime_background.9.png
Binary files differ
diff --git a/res/drawable-mdpi/btn_keyboard_key_normal.9.png b/res/drawable-mdpi/btn_keyboard_key_normal.9.png
index d0f9b7cc6..7ba18dd25 100644
--- a/res/drawable-mdpi/btn_keyboard_key_normal.9.png
+++ b/res/drawable-mdpi/btn_keyboard_key_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi/btn_keyboard_key_pressed.9.png b/res/drawable-mdpi/btn_keyboard_key_pressed.9.png
index 91809e242..39b9314a1 100755..100644
--- a/res/drawable-mdpi/btn_keyboard_key_pressed.9.png
+++ b/res/drawable-mdpi/btn_keyboard_key_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_mic_dialog.png b/res/drawable-mdpi/ic_mic_dialog.png
new file mode 100644
index 000000000..77613ca05
--- /dev/null
+++ b/res/drawable-mdpi/ic_mic_dialog.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_suggest_strip_microphone.png b/res/drawable-mdpi/ic_suggest_strip_microphone.png
new file mode 100644
index 000000000..18f314a61
--- /dev/null
+++ b/res/drawable-mdpi/ic_suggest_strip_microphone.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_suggest_strip_microphone_swipe.png b/res/drawable-mdpi/ic_suggest_strip_microphone_swipe.png
new file mode 100644
index 000000000..ff629b674
--- /dev/null
+++ b/res/drawable-mdpi/ic_suggest_strip_microphone_swipe.png
Binary files differ
diff --git a/res/drawable-mdpi/list_selector_background_pressed.9.png b/res/drawable-mdpi/list_selector_background_pressed.9.png
new file mode 100644
index 000000000..02b4e9a53
--- /dev/null
+++ b/res/drawable-mdpi/list_selector_background_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_123_mic.png b/res/drawable-mdpi/sym_keyboard_123_mic.png
new file mode 100644
index 000000000..35afe0821
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_123_mic.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_feedback_123_mic.png b/res/drawable-mdpi/sym_keyboard_feedback_123_mic.png
new file mode 100644
index 000000000..bc11cf31a
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_feedback_123_mic.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_left.png b/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_left.png
new file mode 100644
index 000000000..e3f80fada
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_left.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_right.png b/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_right.png
new file mode 100644
index 000000000..3cb0d9913
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_right.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_feedback_mic.png b/res/drawable-mdpi/sym_keyboard_feedback_mic.png
new file mode 100644
index 000000000..247d5b3a9
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_feedback_mic.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_feedback_tab.png b/res/drawable-mdpi/sym_keyboard_feedback_tab.png
new file mode 100644
index 000000000..593fa6703
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_feedback_tab.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_feedback_tabprev.png b/res/drawable-mdpi/sym_keyboard_feedback_tabprev.png
new file mode 100644
index 000000000..d4b3e7db3
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_feedback_tabprev.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_globe.png b/res/drawable-mdpi/sym_keyboard_globe.png
new file mode 100644
index 000000000..f30c1b640
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_globe.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_language_arrows_left.png b/res/drawable-mdpi/sym_keyboard_language_arrows_left.png
new file mode 100644
index 000000000..91eda5f2d
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_language_arrows_left.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_language_arrows_right.png b/res/drawable-mdpi/sym_keyboard_language_arrows_right.png
new file mode 100644
index 000000000..62a5beba4
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_language_arrows_right.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_mic.png b/res/drawable-mdpi/sym_keyboard_mic.png
new file mode 100644
index 000000000..a75809549
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_mic.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_num7.png b/res/drawable-mdpi/sym_keyboard_num7.png
index 4d75583af..ce800ba42 100644
--- a/res/drawable-mdpi/sym_keyboard_num7.png
+++ b/res/drawable-mdpi/sym_keyboard_num7.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_tab.png b/res/drawable-mdpi/sym_keyboard_tab.png
new file mode 100644
index 000000000..cd9daff08
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_tab.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_keyboard_tabprev.png b/res/drawable-mdpi/sym_keyboard_tabprev.png
new file mode 100644
index 000000000..eb90872fc
--- /dev/null
+++ b/res/drawable-mdpi/sym_keyboard_tabprev.png
Binary files differ
diff --git a/res/drawable/cancel.png b/res/drawable/cancel.png
new file mode 100644
index 000000000..081532bec
--- /dev/null
+++ b/res/drawable/cancel.png
Binary files differ
diff --git a/res/drawable/caution.png b/res/drawable/caution.png
new file mode 100644
index 000000000..eaef53425
--- /dev/null
+++ b/res/drawable/caution.png
Binary files differ
diff --git a/res/drawable/dialog_top_dark_bottom_medium.9.png b/res/drawable/dialog_top_dark_bottom_medium.9.png
new file mode 100644
index 000000000..cf7ecaf1e
--- /dev/null
+++ b/res/drawable/dialog_top_dark_bottom_medium.9.png
Binary files differ
diff --git a/res/drawable/ic_dialog_alert_large.png b/res/drawable/ic_dialog_alert_large.png
new file mode 100644
index 000000000..2d4a164a7
--- /dev/null
+++ b/res/drawable/ic_dialog_alert_large.png
Binary files differ
diff --git a/res/drawable/ic_dialog_voice_input.png b/res/drawable/ic_dialog_voice_input.png
new file mode 100644
index 000000000..d28914132
--- /dev/null
+++ b/res/drawable/ic_dialog_voice_input.png
Binary files differ
diff --git a/res/drawable/ic_dialog_wave_0_0.png b/res/drawable/ic_dialog_wave_0_0.png
new file mode 100644
index 000000000..9c3c28f37
--- /dev/null
+++ b/res/drawable/ic_dialog_wave_0_0.png
Binary files differ
diff --git a/res/drawable/ic_dialog_wave_1_3.png b/res/drawable/ic_dialog_wave_1_3.png
new file mode 100644
index 000000000..d33bd0d9b
--- /dev/null
+++ b/res/drawable/ic_dialog_wave_1_3.png
Binary files differ
diff --git a/res/drawable/ic_dialog_wave_2_3.png b/res/drawable/ic_dialog_wave_2_3.png
new file mode 100644
index 000000000..5094a6e6c
--- /dev/null
+++ b/res/drawable/ic_dialog_wave_2_3.png
Binary files differ
diff --git a/res/drawable/ic_dialog_wave_3_3.png b/res/drawable/ic_dialog_wave_3_3.png
new file mode 100644
index 000000000..69917564d
--- /dev/null
+++ b/res/drawable/ic_dialog_wave_3_3.png
Binary files differ
diff --git a/res/drawable/ic_dialog_wave_4_3.png b/res/drawable/ic_dialog_wave_4_3.png
new file mode 100644
index 000000000..af5a84c31
--- /dev/null
+++ b/res/drawable/ic_dialog_wave_4_3.png
Binary files differ
diff --git a/res/drawable/mic_slash.png b/res/drawable/mic_slash.png
new file mode 100644
index 000000000..0b0fb5803
--- /dev/null
+++ b/res/drawable/mic_slash.png
Binary files differ
diff --git a/res/drawable/ok_cancel.png b/res/drawable/ok_cancel.png
new file mode 100644
index 000000000..0601d3231
--- /dev/null
+++ b/res/drawable/ok_cancel.png
Binary files differ
diff --git a/res/drawable/speak_now_level0.png b/res/drawable/speak_now_level0.png
new file mode 100644
index 000000000..abc845466
--- /dev/null
+++ b/res/drawable/speak_now_level0.png
Binary files differ
diff --git a/res/drawable/speak_now_level1.png b/res/drawable/speak_now_level1.png
new file mode 100644
index 000000000..67cb235bf
--- /dev/null
+++ b/res/drawable/speak_now_level1.png
Binary files differ
diff --git a/res/drawable/speak_now_level2.png b/res/drawable/speak_now_level2.png
new file mode 100644
index 000000000..1e07f26c6
--- /dev/null
+++ b/res/drawable/speak_now_level2.png
Binary files differ
diff --git a/res/drawable/speak_now_level3.png b/res/drawable/speak_now_level3.png
new file mode 100644
index 000000000..31991daee
--- /dev/null
+++ b/res/drawable/speak_now_level3.png
Binary files differ
diff --git a/res/drawable/speak_now_level4.png b/res/drawable/speak_now_level4.png
new file mode 100644
index 000000000..7363ca892
--- /dev/null
+++ b/res/drawable/speak_now_level4.png
Binary files differ
diff --git a/res/drawable/speak_now_level5.png b/res/drawable/speak_now_level5.png
new file mode 100644
index 000000000..9034908f4
--- /dev/null
+++ b/res/drawable/speak_now_level5.png
Binary files differ
diff --git a/res/drawable/speak_now_level6.png b/res/drawable/speak_now_level6.png
new file mode 100644
index 000000000..3eaa9bdad
--- /dev/null
+++ b/res/drawable/speak_now_level6.png
Binary files differ
diff --git a/res/drawable/voice_ime_background.9.png b/res/drawable/voice_ime_background.9.png
new file mode 100644
index 000000000..67802492a
--- /dev/null
+++ b/res/drawable/voice_ime_background.9.png
Binary files differ
diff --git a/res/drawable/voice_swipe_hint.png b/res/drawable/voice_swipe_hint.png
new file mode 100644
index 000000000..bb8873251
--- /dev/null
+++ b/res/drawable/voice_swipe_hint.png
Binary files differ
diff --git a/res/drawable/working.png b/res/drawable/working.png
new file mode 100644
index 000000000..6246a6d1c
--- /dev/null
+++ b/res/drawable/working.png
Binary files differ
diff --git a/res/layout/candidates.xml b/res/layout/candidates.xml
index 39df81dd2..068c17e56 100755
--- a/res/layout/candidates.xml
+++ b/res/layout/candidates.xml
@@ -21,29 +21,29 @@
<com.android.inputmethod.latin.CandidateViewContainer
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/candidate_strip_height"
android:background="@drawable/keyboard_suggest_strip"
>
<LinearLayout
android:id="@+id/candidate_left_parent"
android:layout_width="wrap_content"
- android:layout_height="fill_parent"
+ android:layout_height="match_parent"
android:orientation="horizontal">
<ImageButton
android:id="@+id/candidate_left"
android:background="@drawable/ic_suggest_scroll_background"
android:src="@drawable/ic_suggest_strip_scroll_left_arrow"
android:layout_width="36dp"
- android:layout_height="fill_parent"
+ android:layout_height="match_parent"
android:clickable="true"
/>
<ImageView
android:src="@drawable/keyboard_suggest_strip_divider"
android:layout_width="wrap_content"
- android:layout_height="fill_parent"
+ android:layout_height="match_parent"
/>
</LinearLayout>
@@ -57,13 +57,13 @@
<LinearLayout
android:id="@+id/candidate_right_parent"
android:layout_width="wrap_content"
- android:layout_height="fill_parent"
+ android:layout_height="match_parent"
android:clickable="true"
android:orientation="horizontal">
<ImageView
android:src="@drawable/keyboard_suggest_strip_divider"
android:layout_width="wrap_content"
- android:layout_height="fill_parent"
+ android:layout_height="match_parent"
/>
<ImageButton
@@ -71,9 +71,9 @@
android:background="@drawable/ic_suggest_scroll_background"
android:src="@drawable/ic_suggest_strip_scroll_right_arrow"
android:layout_width="36dp"
- android:layout_height="fill_parent"
+ android:layout_height="match_parent"
android:clickable="true"
/>
</LinearLayout>
-</com.android.inputmethod.latin.CandidateViewContainer> \ No newline at end of file
+</com.android.inputmethod.latin.CandidateViewContainer>
diff --git a/res/layout/input.xml b/res/layout/input.xml
index f2f30ca84..1d7c6f746 100755
--- a/res/layout/input.xml
+++ b/res/layout/input.xml
@@ -22,7 +22,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/keyboardView"
android:layout_alignParentBottom="true"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/keyboard_background"
android:keyBackground="@drawable/btn_keyboard_key"
diff --git a/res/layout/recognition_status.xml b/res/layout/recognition_status.xml
new file mode 100644
index 000000000..ea23824a1
--- /dev/null
+++ b/res/layout/recognition_status.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, 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:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:background="@android:color/black"
+ android:paddingBottom="0dip"
+ android:paddingLeft="0dip"
+ android:paddingRight="0dip"
+>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main_image"
+ android:orientation="vertical"
+ android:background="@drawable/voice_ime_background"
+ android:scaleType="fitXY"
+ android:layout_width="match_parent"
+ android:layout_height="180dip"
+ android:paddingBottom="2dip"
+ android:paddingTop="2dip"
+ >
+
+ <TextView android:id="@+id/text"
+ android:text="@string/voice_initializing"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="15dip"
+ android:textSize="28sp"
+ android:textColor="#ffffff"
+ android:layout_gravity="center_horizontal"
+ />
+
+ <ImageView android:id="@+id/image"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="20dip"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/mic_slash"
+ />
+
+ <ProgressBar android:id="@+id/progress"
+ android:layout_height="60dip"
+ android:layout_width="60dip"
+ android:layout_marginTop="20dip"
+ android:layout_gravity="center_horizontal"
+ android:visibility="gone"
+ android:indeterminate="true"
+ />
+
+
+
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/button"
+ android:orientation="vertical"
+ android:background="@drawable/ok_cancel"
+ android:scaleType="fitXY"
+ android:layout_width="match_parent"
+ android:layout_height="42dip"
+ android:paddingLeft="1dip"
+ android:paddingRight="1dip"
+ >
+
+ <TextView android:id="@+id/button_text"
+ android:text="@string/cancel"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="7dip"
+ android:textSize="19sp"
+ android:textColor="#ffffff"
+ android:layout_gravity="center_horizontal"
+ />
+ </LinearLayout>
+
+</LinearLayout>
+
diff --git a/res/layout/voice_punctuation_hint.xml b/res/layout/voice_punctuation_hint.xml
new file mode 100644
index 000000000..629a7f2b5
--- /dev/null
+++ b/res/layout/voice_punctuation_hint.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, 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:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/keyboard_suggest_strip">
+
+ <!-- TODO: Use dark mic icon. -->
+ <ImageView android:id="@+id/image"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/ic_suggest_strip_microphone"
+ />
+
+ <TextView android:id="@+id/text"
+ android:text="@string/voice_punctuation_hint"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingTop="2dip"
+ android:paddingRight="3dip"
+ android:textSize="13sp"
+ android:textColor="#888888"
+ android:layout_gravity="center_horizontal"
+ />
+
+</LinearLayout>
diff --git a/res/layout/voice_swipe_hint.xml b/res/layout/voice_swipe_hint.xml
new file mode 100644
index 000000000..4e8859a71
--- /dev/null
+++ b/res/layout/voice_swipe_hint.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, 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:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/keyboard_suggest_strip"
+ android:gravity="center_horizontal"
+ android:paddingTop="2dip">
+
+ <TextView android:id="@+id/text"
+ android:text="@string/voice_swipe_hint"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingTop="10dip"
+ android:paddingRight="6dip"
+ android:textSize="13sp"
+ android:textColor="#888888"
+ android:layout_gravity="center_horizontal"
+ />
+
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/ic_suggest_strip_microphone"
+ />
+
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/ic_suggest_strip_microphone_swipe"
+ />
+
+
+</LinearLayout>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 38ac20200..75bdda152 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Základní"</item>
<item msgid="4894328801530136615">"Pokročilé"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uloženo"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"áàâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"éěèêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ňñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"čç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Podržením klávesy zobrazíte diakritiku (ž, á atd.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Stisknutím klávesy Zpět ↶ můžete klávesnici kdykoli zavřít"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Přístup k číslům a symbolům"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"Alt"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Hlasový vstup"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Pro váš jazyk aktuálně není hlasový vstup podporován, ale funguje v angličtině."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Hlasový vstup je experimentální funkce, která využívá síťové rozpoznávání řeči společnosti Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Chcete-li vypnout hlasový vstup, přejděte do nastavení klávesnice."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Chcete-li použít hlasový vstup, stiskněte tlačítko mikrofonu nebo přejeďte prstem přes klávesnici na obrazovce."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Mluvte"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Probíhá zpracování"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Chyba. Zkuste to prosím znovu."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Připojení se nezdařilo."</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Chyba, řeč je příliš dlouhá."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problém se zvukem"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Chyba serveru"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Nebyla detekována žádná řeč."</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Nebyly nalezeny žádné shody"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Hlasové vyhledávání není nainstalováno"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Nápověda:"</b>" Chcete-li aktivovat hlasový vstup, přejeďte prstem přes klávesnici."</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Nápověda:"</b>" Příště zkuste vyslovit interpunkci, například „tečka“, „čárka“ nebo „otazník“."</string>
+ <string name="cancel" msgid="6830980399865683324">"Zrušit"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Hlasový vstup"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Po hlasovém vstupu automaticky odeslat"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Při vyhledávání nebo přechodu na další pole automaticky stisknout Enter."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Otevřete klávesnici"\n</b></font><font size="3">\n</font>"Dotkněte se jakéhokoli textového pole."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Zavřete klávesnici"\n</b></font><font size="3">\n</font>"Stiskněte klávesu Zpět."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Přidržením klávesy zobrazte možnosti"\n</b></font><font size="3">\n</font>"Použijte interpunkční znaménka a diakritiku."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".net"</string>
<string name="popular_domain_4" msgid="35359437471311470">".eu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Metoda zadávání dat"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index d4dd23a65..70ba54729 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Grundlæggende"</item>
<item msgid="4894328801530136615">"Avanceret"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Gemt"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Hold en tast nede for at se accenter (ø, ö osv.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Tryk på tilbagetasten ↶ for når som helst at lukke for tastaturet"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Få adgang til tal og symboler"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Stemmeinput"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmeinput understøttes i øjeblikket ikke for dit sprog, men fungerer på engelsk."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Stemme-input er en funktion på forsøgsbasis, som bruger Googles netværksstemmegenkendelse."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Slå stemmeinput fra i indstillingerne for tastaturet."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"For at bruge stemme-input skal du trykke på knappen mikrofon eller lade glide fingeren hen over skærmtastaturet."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Tal nu"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Arbejder"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Fejl. Prøv igen."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Kunne ikke oprette forbindelse"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Fejl. For meget tale."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Lydproblem"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Serverfejl"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Der høres ingen tale"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Der blev ikke fundet nogen matches"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Stemmesøgning er ikke installeret"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Tip:"</b>" Glid hen over tastaturet for at tale"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Tip:"</b>" Næste gang kan du forsøge at sige tegnsætning, f.eks. \"punktum\", \"komma\" eller \"spørgsmålstegn\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Annuller"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Stemmeinput"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Send automatisk efter stemme"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Tryk automatisk på enter, når du søger eller går til det næste felt."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Åbn tastaturet"\n</b></font><font size="3">\n</font>"Tryk på et hvilket som helst tekstfelt."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Luk tastaturet"\n</b></font><font size="3">\n</font>"Tryk på Tilbagetasten."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Tryk på og hold en tast nede for valgmuligheder"\n</b></font><font size="3">\n</font>"Få adgang til tegnsætning og accenter."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Inputmetode"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index aa52380b6..1d821899e 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Standard"</item>
<item msgid="4894328801530136615">"Erweitert"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Gespeichert"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"ä"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Zur Anzeige von Umlauten (ä, ö usw.) Taste gedrückt halten"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Zum Schließen der Tastatur ↶ drücken"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Auf Zahlen und Symbole zugreifen"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Spracheingabe"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spracheingaben werden derzeit nicht für Ihre Sprache unterstützt, funktionieren jedoch in Englisch."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Die Spracheingabe ist eine Funktion im Versuchsstadium, die die vernetzte Spracherkennung von Google verwendet."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Wenn Sie die Spracheingabe deaktivieren möchten, rufen Sie die Tastatureinstellungen auf."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Um die Spracheingabe zu verwenden, drücken Sie den Mikrofonknopf oder ziehen Sie Ihren Finger über die Bildschirmtastatur."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Jetzt sprechen"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Vorgang läuft"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Fehler. Versuchen Sie es erneut.."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Keine Verbindung"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Fehler – Text zu lang"</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Audio-Problem"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Serverfehler"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Keine Sprache zu hören"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Keine Übereinstimmungen gefunden"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Sprach-Suche nicht installiert"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Hinweis:"</b>" Ziehen Sie zum Sprechen den Finger über die Tastatur."</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Hinweis:"</b>" Versuchen Sie beim nächsten Mal, Satzzeichen wie \"Punkt\", \"Komma\" oder \"Fragezeichen\" per Sprachbefehl einzugeben."</string>
+ <string name="cancel" msgid="6830980399865683324">"Abbrechen"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Spracheingabe"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Nach Sprachaufnahme automatisch senden"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Drücken Sie auf die Eingabetaste, wenn Sie einen Suchvorgang durchführen oder zum nächsten Feld wechseln."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Tastatur öffnen"\n</b></font><font size="3">\n</font>"Berühren Sie ein beliebiges Textfeld."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Tastatur schließen"\n</b></font><font size="3">\n</font>"Drücken Sie die Taste \"Zurück\"."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Eine Taste für Optionen berühren und gedrückt halten"\n</b></font><font size="3">\n</font>"Greifen Sie auf Satzzeichen und Akzente zu."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Eingabemethode"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 173b384b3..acbe2945b 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Βασική"</item>
<item msgid="4894328801530136615">"Σύνθετη"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Αποθηκεύτηκε"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Κρατήστε πατημένο ένα πλήκτρο για να δείτε τους τονισμένους χαρακτήρες (ø, ö, κ.τ.λ.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Πατήστε το πλήκτρο Πίσω ↶ για να κλείσετε το πληκτρολόγιο ανά πάσα στιγμή"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Πρόσβαση σε αριθμούς και σύμβολα"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ΑΒΓ"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Φωνητική είσοδος"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Η φωνητική είσοδος δεν υποστηρίζεται αυτή τη στιγμή για τη γλώσσα σας, ωστόσο λειτουργεί στα Αγγλικά."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Οι φωνητικές εντολές είναι μια πειραματική λειτουργία, η οποία χρησιμοποιεί τη δικτυακή αναγνώριση ομιλίας της Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Για να απενεργοποιήσετε τη φωνητική είσοδο, μεταβείτε στις ρυθμίσεις πληκτρολογίου."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Για να χρησιμοποιήσετε τις φωνητικές εντολές, πιέστε το κουμπί μικροφώνου ή σύρετε το δάχτυλό σας κατά μήκος του πληκτρολογίου της οθόνης."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Μιλήστε τώρα"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Σε λειτουργία"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Σφάλμα. Δοκιμάστε ξανά."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Δεν ήταν δυνατή η σύνδεση"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Σφάλμα, πολλές λέξεις."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Πρόβλημα ήχου"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Σφάλμα διακομιστή"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Δεν ακούγεται ομιλία"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Δεν βρέθηκε καμία αντιστοίχιση"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Η Αναζήτηση με φωνή δεν εγκαταστάθηκε"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Υπόδειξη:"</b>" Σύρετε κατά μήκος του πληκτρολογίου για να μιλήσετε"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Υπόδειξη:"</b>" Την επόμενη φορά, προσπαθήστε να προφέρετε σημεία στίξης, όπως \"τελεία\", \"κόμμα\" ή \"ερωτηματικό\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Ακύρωση"</string>
+ <string name="ok" msgid="7898366843681727667">"ΟΚ"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Φωνητική είσοδος"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Αυτόματη υποβολή μετά από ήχο"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Πατήστε enter αυτόματα κατά την αναζήτηση ή τη μετάβαση στο επόμενο πεδίο."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Ανοίξτε το πληκτρολόγιο"\n</b></font><font size="3">\n</font>"Αγγίξτε οποιοδήποτε πεδίο κειμένου."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Κλείστε το πληκτρολόγιο"\n</b></font><font size="3">\n</font>"Πατήστε το πλήκτρο Πίσω."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Αγγίξτε και κρατήστε ένα πλήκτρο για ορισμό επιλογών"\n</b></font><font size="3">\n</font>"Πρόσβαση στα σημεία στίξης και τονισμού."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Μέθοδος εισόδου"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 6dee06bff..8a8ded8f9 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Básico"</item>
<item msgid="4894328801530136615">"Avanzado"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Mantén una tecla presionada para ver los acentos (ø, ö, etc.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Pulsa la tecla hacia atrás ↶ para cerrar el teclado en cualquier momento"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Acceder a números y símbolos"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Entrada por voz"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La entrada por voz no está admitida en tu idioma, pero sí funciona en inglés."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"La entrada por voz es una característica experimental que utiliza la red de reconocimiento de voz de Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desactivar la entrada por voz, ve a configuración del teclado."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para realizar entrada por voz, presiona el botón del micrófono o desliza tus dedos por el teclado en pantalla."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Habla ahora"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Procesando"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Error. Vuelve a intentarlo."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"No se pudo establecer la conexión."</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Error, demasiado discurso."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problema de audio"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Error del servidor"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"No se oyó la voz"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"No se encontraron coincidencias"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Búsqueda por voz no instalada"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Sugerencia:"</b>" Deslizar en el teclado para hablar"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Sugerencia:"</b>" La próxima vez intenta decir la puntuación como \"punto\", \"coma\" o \"signo de pregunta\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
+ <string name="ok" msgid="7898366843681727667">"Aceptar"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Entrada por voz"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Enviar automáticamente después del audio"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Presionar automáticamente Ingresar al buscar o ir al campo siguiente."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Abrir el teclado"\n</b></font><font size="3">\n</font>"Tocar cualquier campo de texto."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Cerrar el teclado"\n</b></font><font size="3">\n</font>"Presionar la tecla Atrás."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Tocar &amp; y mantener presionada una tecla para las opciones"\n</b></font><font size="3">\n</font>"Acceder a puntuación y acentos."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Método de entrada"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index faedf7e03..4977cbac5 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Básico"</item>
<item msgid="4894328801530136615">"Avanzado"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Guardada"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"á"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"é"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Mantén pulsada una tecla para ver los caracteres acentuados (ø, ö, etc.)."</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Pulsa la tecla \"Atrás\" ↶ para cerrar el teclado en cualquier momento."</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Acceso a números y símbolos"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Introducción de voz"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente la introducción de voz no está disponible en tu idioma, pero se puede utilizar en inglés."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"La introducción de voz es una función en fase experimental que utiliza la tecnología de reconocimiento de voz en red de Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desactivar la función de introducción de voz, accede a la configuración del teclado."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para utilizar la función de introducción de voz, pulsa el botón de micrófono o desliza el dedo por el teclado en pantalla."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Hablar ahora"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Trabajando"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Se ha producido un error. Inténtalo de nuevo."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"No se ha podido establecer conexión."</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Se ha producido un error debido a un exceso de introducción de datos de voz."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problema de audio"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Error del servidor"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Ninguna conversación escuchada"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"No se ha encontrado ninguna coincidencia."</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"La búsqueda por voz no está instalada."</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Sugerencia:"</b>" muévete por el teclado para hablar."</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Sugerencia:"</b>" la próxima vez, prueba a indicar signos de puntuación como, por ejemplo, \"punto\", \"coma\" o \"signo de interrogación\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
+ <string name="ok" msgid="7898366843681727667">"Aceptar"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Introducción de voz"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Enviar automáticamente después de la introducción de voz"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Pulsar Intro automáticamente al buscar o al pasar al siguiente campo"</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Abrir el teclado"\n</b></font><font size="3">\n</font>"Pulsa cualquier campo de texto."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Cerrar el teclado"\n</b></font><font size="3">\n</font>"Pulsa la tecla \"Atrás\"."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Mantén pulsada una tecla para acceder a las opciones."\n</b></font><font size="3">\n</font>"Accede a los signos de puntuación y a los acentos."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Método de introducción de texto"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000..b56463ed9
--- /dev/null
+++ b/res/values-fr-rCA/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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">
+ <string name="english_ime_name" msgid="7252517407088836577">"Clavier Android"</string>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 226c4fb0b..f4834da13 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Simple"</item>
<item msgid="4894328801530136615">"Avancé"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Maintenir une touche enfoncée pour afficher les accents (à, é, etc.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Appuyez sur la touche Retour ↶ pour fermer le clavier à tout moment."</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Accéder aux chiffres et symboles"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Saisie vocale"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La saisie vocale n\'est pas encore prise en charge pour votre langue, mais elle fonctionne en anglais."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"La saisie vocale est une fonctionnalité expérimentale qui fait appel à la reconnaissance vocale en réseau de Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Pour désactiver la saisie vocale, accédez aux paramètres du clavier."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Pour utiliser la saisie vocale, appuyez sur la touche du microphone ou faites glisser votre doigt sur le clavier à l\'écran."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Parlez maintenant"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Traitement en cours"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Erreur. Veuillez réessayer."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Connexion impossible"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Erreur, discours trop long."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problème audio"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Erreur serveur"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Aucune requête vocale détectée"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Aucune correspondance n\'a été trouvée."</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Recherche vocale non installée"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Astuce :"</b>" Faites glisser votre doigt sur le clavier pour parler."</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Astuce :"</b>" La prochaine fois, essayez de prononcer la ponctuation, en énonçant des termes tels que \"point\", \"virgule\" ou \"point d\'interrogation\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Annuler"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Saisie vocale"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Envoi automatique après la saisie vocale"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Appuyez automatiquement sur Entrée pour effectuer une recherche ou accéder au champ suivant."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Ouvrir le clavier"\n</b></font><font size="3">\n</font>"Appuyez sur un champ de texte."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Fermer le clavier"\n</b></font><font size="3">\n</font>"Appuyez sur la touche Retour."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Appuyer sur une touche de manière prolongée pour accéder aux options"\n</b></font><font size="3">\n</font>"Accédez aux signes de ponctuation et aux accents."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gouv"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Mode de saisie"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 62128e4c5..94478ce88 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Base"</item>
<item msgid="4894328801530136615">"Avanzate"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : parola salvata"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àá"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èé"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Tieni premuto un tasto per vedere le lettere con segni diacritici (ø, ö etc.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Premi il tasto Indietro ↶ per chiudere la tastiera"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Accedi a numeri e simboli"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Comandi vocali"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"I comandi vocali non sono attualmente supportati per la tua lingua ma funzionano in inglese."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"I comandi vocali sono una funzione sperimentale che utilizza il riconoscimento vocale in rete di Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Per disattivare i comandi vocali, vai alle impostazioni della tastiera."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Per utilizzare i comandi vocali, premi il pulsante del microfono o fai scorrere il dito sulla tastiera sullo schermo."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Parla ora"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Elaborazione in corso"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Errore. Riprova più tardi."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Impossibile connettersi."</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Errore: conversazione troppo lunga."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problema audio"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Errore del server"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Nessuna frase vocale rilevata"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Nessuna corrispondenza trovata"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Ricerca vocale non installata"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Suggerimento."</b>" Fai scorrere il dito sulla tastiera per parlare"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Suggerimento."</b>" La prossima volta, prova a pronunciare termini relativi alla punteggiatura come \"punto\", \"virgola\" o \"punto di domanda\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Annulla"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Comandi vocali"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Invia automaticamente dopo comando vocale"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Premi automaticamente \"Invio\" durante una ricerca o un passaggio al campo successivo."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Apertura tastiera"\n</b></font><font size="3">\n</font>"Tocca qualsiasi campo di testo."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Chiusura tastiera"\n</b></font><font size="3">\n</font>"Premi il tasto Indietro."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Tocca e tieni premuto un tasto per le opzioni"\n</b></font><font size="3">\n</font>"Accesso a punteggiatura e accenti."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Metodo inserimento"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index e28fcee29..3f29eb96b 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"基本"</item>
<item msgid="4894328801530136615">"高度"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:保存しました"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"キー長押しでアクセント文字を表示(ø、öなど)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"戻るキーでキーボードを閉じます"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"数字と記号"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"音声入力"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"音声入力は現在英語には対応していますが、日本語には対応していません。"</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"音声入力はGoogleのネットワーク音声認識技術を利用した試験段階の機能です。"</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"音声入力をOFFにするには、キーボードの設定を開きます。"</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"音声入力するには、マイクボタンを押すか画面キーボードをスワイプしてください。"</string>
+ <string name="voice_listening" msgid="467518160751321844">"お話しください"</string>
+ <string name="voice_working" msgid="6666937792815731889">"処理中"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"エラーです。もう一度お試しください。"</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"接続できませんでした"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"音声が長すぎてエラーになりました。"</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"オーディオエラー"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"サーバーエラー"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"音声が聞き取れません"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"該当なし"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Voice Searchはインストールされていません"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"ヒント:"</b>" 音声入力するにはキーボードをスワイプします"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"ヒント:"</b>" 次回は句読点として「period」、「comma」、「question mark」などの音声入力を試してみてください。"</string>
+ <string name="cancel" msgid="6830980399865683324">"キャンセル"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"音声入力"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"入力後に自動送信する"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"検索または次のフィールドに進む際、Enterキーが自動的に押されます。"</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"キーボードを開く"\n</b></font><font size="3">\n</font>"テキストフィールドをタップします。"</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"キーボードを閉じる"\n</b></font><font size="3">\n</font>"[戻る]キーを押します。"</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"キーを長押しして選択する"\n</b></font><font size="3">\n</font>"句読点キーとアクセント文字を表示します。"</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"入力方法"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index e86c609ad..1d9e0bd30 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"기본"</item>
<item msgid="4894328801530136615">"고급"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : 저장됨"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"키를 길게 누르면 악센트(ø, ö 등)가 표시됩니다."</string>
<string name="tip_dismiss" msgid="7585579046862204381">"키보드를 닫으려면 언제든지 뒤로 키(↶)를 누르세요."</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"숫자 및 기호 액세스"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"음성 입력"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"음성 입력은 현재 자국어로 지원되지 않으며 영어로 작동됩니다."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"음성 입력은 Google의 네트워크화된 음성 인식을 사용하는 실험적 기능입니다."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"음성 입력을 사용하지 않으려면 키보드 설정으로 이동하세요."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"음성 입력을 사용하려면 마이크 버튼을 누르거나 터치 키보드 위로 손가락을 미끄러지듯 움직이세요."</string>
+ <string name="voice_listening" msgid="467518160751321844">"지금 시작하세요."</string>
+ <string name="voice_working" msgid="6666937792815731889">"인식 중"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"오류가 발생했습니다. 다시 시도해 보세요."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"연결할 수 없습니다."</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"음성을 너무 많이 입력했습니다."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"오디오 문제"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"서버 오류"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"음성이 인식되지 않았습니다."</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"일치하는 항목 없음"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"음성 검색이 설치되지 않았습니다."</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"도움말:"</b>" 키보드를 스와이프하고 말하세요."</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"도움말:"</b>" 다음 번에는 \'마침표\', \'쉼표\', \'물음표\'와 같은 구두점을 말해 보세요."</string>
+ <string name="cancel" msgid="6830980399865683324">"취소"</string>
+ <string name="ok" msgid="7898366843681727667">"확인"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"음성 입력"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"음성을 입력한 다음 자동 제출"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"검색하거나 다음 입력란으로 이동할 때 자동으로 Enter 키를 누릅니다."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"키보드 열기"\n</b></font><font size="3">\n</font>"아무 텍스트 입력란이나 터치하세요."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"키보드 닫기"\n</b></font><font size="3">\n</font>"\'뒤로\' 키를 누르세요."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"키를 길게 터치하여 옵션 보기"\n</b></font><font size="3">\n</font>"문장 부호 및 악센트 기호에 액세스하세요."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"입력 방법"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index bafc613f6..971bc1445 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Grunnleggende"</item>
<item msgid="4894328801530136615">"Avansert"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Lagret"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"åæáàâãä"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"éèêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Hold en tast nede for å se aksenterte tegn (ø, ö, osv.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Trykk tilbakeknappen, ↶, for å lukke tastaturet"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Få tilgang til tall og symboler"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Stemmedata"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmedata håndteres foreløpig ikke på ditt språk, men fungerer på engelsk."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Talekommandoer er en eksperimentell funksjon som bruker Googles nettverksbaserte talegjenkjenning."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Gå til innstillinger for tastatur for å slå av stemmedata."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Du bruker talekommandoer ved å trykke på mikrofonknappen eller skyve fingeren over tastaturet på skjermen."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Snakk nå"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Arbeider"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Feil. Prøv på nytt."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Kunne ikke koble til"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Feil – for mye tale"</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Lydproblem"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Tjenerfeil"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Ingen tale høres"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Ingen treff"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Talesøk ikke installert"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021">"Hint:"<b>" Sveip over tastaturet for å snakke"</b></string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Hint:"</b>" Neste gang kan du prøve å tale inn tegnsettingen ved for eksempel å si «punktum», «komma» eller «spørsmålstegn»."</string>
+ <string name="cancel" msgid="6830980399865683324">"Avbryt"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Stemmedata"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Send inn automatisk etter tale"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Trykk Enter automatisk ved søk eller flytting til neste felt."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Åpne tastaturet"\n</b></font><font size="3">\n</font>"Trykk på et tekstfelt."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Lukke tastaturet"\n</b></font><font size="3">\n</font>"Trykk på tilbaketasten."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Trykk og hold nede en tast for flere valg"\n</b></font><font size="3">\n</font>"Få tilgang til skilletegn og aksenter."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".net"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".org"</string>
<string name="popular_domain_4" msgid="35359437471311470">".info"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Inndatametode"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 427dcf75c..beeb0af11 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Basis"</item>
<item msgid="4894328801530136615">"Geavanceerd"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Opgeslagen"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Houd een toets ingedrukt om diakritische tekens weer te geven (ø, ö, enzovoort)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Druk op elk gewenst moment op de toets Terug ↶ om het toetsenbord te sluiten"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Toegang tot cijfers en symbolen"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"Alt"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Spraakinvoer"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spraakinvoer wordt momenteel niet ondersteund in uw taal, maar is wel beschikbaar in het Engels."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Spraakinvoer is een experimentele functie met de spraakherkenning van het Google-netwerk."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Als u spraakinvoer wilt uitschakelen, gaat u naar de toetsenbordinstellingen."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Als u spraakinvoer gebruikt, drukt u op de microfoonknop of schuift u uw vinger over het schermtoetsenbord."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Nu spreken"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Wordt uitgevoerd"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Fout. Probeer het opnieuw."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Kan geen verbinding maken"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Fout, te lange spraakinvoer."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Audioprobleem"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Serverfout"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Geen spraak te horen"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Geen resultaten gevonden"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Voice Search is niet geïnstalleerd"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Hint:"</b>" schuif over het toetsenbord om te spreken"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Hint:"</b>" spreek de volgende keer interpunctie uit, zoals \'period\' (punt), \'comma\' (komma) of \'question mark\' (vraagteken)."</string>
+ <string name="cancel" msgid="6830980399865683324">"Annuleren"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Spraakinvoer"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Automatisch verzenden na spraak"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Drukt automatisch op Enter tijdens het zoeken of wanneer u naar het volgende veld wilt gaan."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Het toetsenbord openen"\n</b></font><font size="3">\n</font>"Raak een tekstveld aan."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Het toetsenbord sluiten"\n</b></font><font size="3">\n</font>"Druk op de terugtoets."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Een toets blijven aanraken voor opties"\n</b></font><font size="3">\n</font>"Toegang tot interpunctie en diakritische tekens."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Invoermethode"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 663932d38..2da020783 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Podstawowy"</item>
<item msgid="4894328801530136615">"Zaawansowany"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Zapisano"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"ą"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"ę"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ń"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ć"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Przytrzymaj klawisz, aby wyświetlić znaki akcentowane (ą, ó itp.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Naciśnij klawisz cofania ↶, aby zamknąć klawiaturę w dowolnym momencie"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Przejdź do cyfr i symboli"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Wprowadzanie głosowe"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Wprowadzanie głosowe obecnie nie jest obsługiwane w Twoim języku, ale działa w języku angielskim."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Wprowadzanie głosowe to funkcja eksperymentalna wykorzystująca funkcję firmy Google umożliwiającą rozpoznawanie mowy przy użyciu sieci."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Aby wyłączyć wprowadzanie głosowe, przejdź do ustawień klawiatury."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Aby skorzystać z wprowadzania głosowego, naciśnij przycisk mikrofonu lub przesuń palcem po klawiaturze ekranowej."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Mów teraz"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Działa"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Błąd. Spróbuj ponownie."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Nie można nawiązać połączenia"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Błąd, zbyt długa wypowiedź."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problem z dźwiękiem"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Błąd serwera"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Nie wykryto mowy"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Nie znaleziono żadnych wyników"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Wyszukiwanie głosowe nie jest zainstalowane"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Wskazówka:"</b>" przesuń palcem po klawiaturze, aby mówić."</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Wskazówka:"</b>" następnym razem spróbuj wypowiadać nazwy znaków interpunkcyjnych: „kropka”, „przecinek” lub „pytajnik”."</string>
+ <string name="cancel" msgid="6830980399865683324">"Anuluj"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Wprowadzanie głosowe"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Automatyczne przesyłanie uruchamiane głosem"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Podczas wyszukiwania lub przechodzenia do następnego pola automatycznie naciśnij klawisz Enter."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Otwórz klawiaturę"\n</b></font><font size="3">\n</font>"Dotknij dowolnego pola tekstowego."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Zamknij klawiaturę"\n</b></font><font size="3">\n</font>"Naciśnij klawisz Wróć."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Dotknij klawisza i przytrzymaj go, aby wyświetlić opcje"\n</b></font><font size="3">\n</font>"Dostęp do znaków przestankowych i akcentowanych."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Metoda wprowadzania"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index da89aeca9..ec397b66f 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Básico"</item>
<item msgid="4894328801530136615">"Avançados"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Guardada"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Mantenha uma tecla premida para ver os acentos (ø, ö, etc.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Prima a tecla de retrocesso ↶ para fechar o teclado a qualquer momento"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Aceder a números e símbolos"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente, a entrada de voz não é suportada para o seu idioma, mas funciona em inglês."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"A entrada de voz é uma funcionalidade experimental que utiliza o reconhecimento de voz em rede da Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desactivar a entrada de voz, aceda às definições do teclado."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para utilizar a entrada de voz, prima o botão do microfone ou deslize o dedo no teclado do ecrã."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Falar agora"</string>
+ <string name="voice_working" msgid="6666937792815731889">"A executar"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Erro. Tente novamente."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Não foi possível ligar"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Erro, discurso demasiado longo."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problema de áudio"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Erro no servidor"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Nenhuma voz ouvida"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Não foram encontradas correspondências"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Pesquisa de voz não instalada"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Sugestão:"</b>" Deslize no teclado para falar"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Sugestão:"</b>" Da próxima vez, experimente dizer a pontuação como \"ponto final\", \"vírgula\" ou \"ponto de interrogação\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Entrada de voz"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Enviar automaticamente depois da voz"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Premir automaticamente ENTER ao pesquisar ou avançar para o campo seguinte."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Abra o teclado"\n</b></font><font size="3">\n</font>"Toque em qualquer campo de texto."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Feche o teclado"\n</b></font><font size="3">\n</font>"Prima a tecla \"Anterior\"."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Mantenha premida uma tecla para as opções"\n</b></font><font size="3">\n</font>"Aceder a pontuação e acentos."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 6995e2272..64042b30b 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Básico"</item>
<item msgid="4894328801530136615">"Avançado"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Salvo"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Segure uma tecla pressionada para ver os acentos (ø, ö, etc.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Apertar a tecla voltar ↶ para fechar o teclado, em qualquer ponto"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Acessar números e símbolos"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"A entrada de voz não é suportada no momento para o seu idioma, mas funciona em inglês."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"A entrada de voz é um recurso experimental que usa o reconhecimento de fala de rede do Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desativar a entrada de voz, vá para as configurações do teclado."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para usar a entrada de voz, pressione o botão com o microfone ou deslize o dedo sobre o teclado na tela."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Fale agora"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Trabalhando"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Erro. Tente novamente."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Não foi possível conectar"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Erro, fala muito longa."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Problema com o áudio"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Erro do servidor"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Nenhuma fala ouvida"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Não há resultados compatíveis"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"A pesquisa por voz não está instalada"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Dica:"</b>" Deslize sobre o teclado para falar"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Dica:"</b>" Da próxima vez, tente falar o nome da pontuação como \"ponto\", \"vírgula\" ou \"ponto de interrogação\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Entrada de voz"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Enviar automaticamente depois de falar"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Pressione Enter automaticamente ao pesquisar ou ir para o próximo campo."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Abra o teclado"\n</b></font><font size="3">\n</font>"Toque em qualquer campo de texto."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Feche o teclado"\n</b></font><font size="3">\n</font>"Pressione a tecla Voltar."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Toque e mantenha pressionada uma tecla para ver as opções"\n</b></font><font size="3">\n</font>"Acesse a pontuação e os acentos."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index de7da45f0..6e81f7d03 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Основной"</item>
<item msgid="4894328801530136615">"Расширенный"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : сохранено"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Удерживайте клавишу, чтобы увидеть варианты с диакритическими знаками (ø, ö и т.д.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Нажмите клавишу \"Назад\" ↶, чтобы закрыть клавиатуру в любой момент"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Открыть цифры и символы"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"АБВ"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Голосовой ввод"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"В настоящее время функция голосового ввода не поддерживает ваш язык, но вы можете пользоваться ей на английском."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Голосовой ввод – экспериментальная функция на основе технологии сетевого распознавания речи от Google."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Функция голосового ввода отключается в настройках клавиатуры."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Чтобы использовать голосовой ввод, нажмите кнопку микрофона или проведите пальцем по экранной клавиатуре."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Говорите"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Выполняется обработка"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Ошибка. Повторите попытку."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Ошибка подключения"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Слишком длинная фраза"</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Неполадка со звуком"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Ошибка сервера"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Речи не слышно"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Соответствий не найдено"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Голосовой поиск не установлен"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Совет"</b>". Проведите пальцем по клавиатуре для голосового ввода."</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Совет"</b>". В следующий раз проговаривайте знаки препинания, например \"точка\", \"запятая\", \"вопросительный знак\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Отмена"</string>
+ <string name="ok" msgid="7898366843681727667">"ОК"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Голосовой ввод"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Автоматически отправлять по окончании голосового ввода"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Автоматически нажимать \"Ввод\" при поиске или переходе к следующему полю."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Откройте клавиатуру"\n</b></font><font size="3">\n</font>"Нажмите на любое текстовое поле."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Закрытие клавиатуры"\n</b></font><font size="3">\n</font>"Нажмите клавишу \"Назад\"."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Нажмите и удерживайте клавишу для вызова параметров"\n</b></font><font size="3">\n</font>"Доступ к пунктуационным и диакритическим знакам."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Способ ввода"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 38fdaf20b..8027eb3f7 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Grundinställningar"</item>
<item msgid="4894328801530136615">"Avancerade"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: sparat"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Håll nere en tangent om du vill visa accenter (ø, ö, etc.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Tryck på Tillbaka ↶ om du vill stänga tangentbordet"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"För siffror och symboler"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Röstindata"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Röstindata stöds inte på ditt språk än, men tjänsten fungerar på engelska."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Röstinmatning är en funktion på experimentstadiet som använder Googles nätverks taligenkänning."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Om du vill stänga av röstindata öppnar du inställningarna för tangentbordet."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Om du vill använda röstinmatning trycker du på mikrofonknappen eller drar fingret över tangentbordet på skärmen."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Tala nu"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Fungerar"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Fel. Försök igen."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Det gick inte att ansluta"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Fel, för mycket tal."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Ljudproblem"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Serverfel"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Hörde inget tal"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Inga träffar hittades"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Voice Search är inte installerat"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Tips!"</b>" Dra över tangentbordet om du vill tala"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Tips!"</b>" Nästa gång testar du att säga skiljetecknen, som \"punkt\", \"komma\" eller \"frågetecken\"."</string>
+ <string name="cancel" msgid="6830980399865683324">"Avbryt"</string>
+ <string name="ok" msgid="7898366843681727667">"OK"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Röstindata"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Skicka automatiskt efter röst"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Tryck automatiskt på retur vid sökning eller när du fortsätter till nästa fält."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Öppna tangentbordet"\n</b></font><font size="3">\n</font>"Tryck på ett textfält."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Stäng tangentbordet"\n</b></font><font size="3">\n</font>"Tryck på Tillbaka."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Tryck länge på en tangent om du vill se alternativ"\n</b></font><font size="3">\n</font>"Använda skiljetecken och accenter."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Indatametod"</string>
</resources>
diff --git a/res/values-tr/donottranslate.xml b/res/values-tr/donottranslate.xml
index f206e4c43..2154c16bb 100644
--- a/res/values-tr/donottranslate.xml
+++ b/res/values-tr/donottranslate.xml
@@ -20,4 +20,4 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Accented characters related to "g" -->
<string name="alternates_for_g">ğ</string>
-</resources>
+</resources> \ No newline at end of file
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index fe5ee893b..069abeb14 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"Temel"</item>
<item msgid="4894328801530136615">"Gelişmiş"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kaydedildi"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"Vurguları görmek için bir tuşu basılı tutun (ø, ö, v.b.)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"Klavyeyi herhangi bir anda kapatmak için geri tuşuna ↶ basın"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"Sayılara ve simgelere erişin"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"Ses girişi"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Ses girişi, şu anda sizin diliniz için desteklenmiyor ama İngilizce dilinde kullanılabilir."</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Ses girişi, Google\'ın ağ bağlantılı ses tanıma işlevini kullanan deneysel bir özelliktir."</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Ses girişini kapatmak için klavye ayarlarına gidin."</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Ses girişini kullanmak için mikrofon düğmesine basın veya parmağınızı dokunmatik klavye üzerinde kaydırın."</string>
+ <string name="voice_listening" msgid="467518160751321844">"Şimdi konuşun"</string>
+ <string name="voice_working" msgid="6666937792815731889">"Çalışıyor"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"Hata. Lütfen tekrar deneyin."</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"Bağlanamadı"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"Hata, çok uzun konuşma."</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"Ses sorunu"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"Sunucu hatası"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"Konuşma duyulmadı"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"Eşleşme bulunamadı"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"Sesle arama yüklenmedi"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"İpucu:"</b>" Konuşmak için parmağınızı klavye üzerinde kaydırın"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"İpucu:"</b>" Sonraki sefer, \"nokta\", \"virgül\" veya \"soru işareti\" gibi noktalama işaretlerini telaffuz etmeyi deneyin."</string>
+ <string name="cancel" msgid="6830980399865683324">"İptal"</string>
+ <string name="ok" msgid="7898366843681727667">"Tamam"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"Ses girişi"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"Sesten sonra otomatik gönder"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"Arama yaparken veya bir sonraki alana giderken enter tuşuna otomatik olarak basın."</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Klavyeyi açın"\n</b></font><font size="3">\n</font>"Herhangi bir metin alanına dokunun."</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Klavyeyi kapatın"\n</b></font><font size="3">\n</font>"Geri tuşuna basın."</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Seçenekler için bir tuşa dokunun ve basılı tutun"\n</b></font><font size="3">\n</font>"Noktalama ve vurgulama işaretlerine erişin."</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"Giriş yöntemi"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index cd01df74a..034f32739 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -27,7 +27,7 @@
<string name="auto_correction_summary" msgid="6881047311475758267">"自动纠正之前的字词"</string>
<string name="prediction" msgid="466220283138359837">"字词建议"</string>
<string name="prediction_category" msgid="7027100625580696660">"字词建议设置"</string>
- <string name="prediction_summary" msgid="459788228830873110">"输入时启用自动完成"</string>
+ <string name="prediction_summary" msgid="459788228830873110">"输入时启用自动填写功能"</string>
<string name="auto_complete_dialog_title" msgid="2172048590607201920">"自动完成"</string>
<string name="prediction_landscape" msgid="4874601565593216183">"增加文本域的大小"</string>
<string name="prediction_landscape_summary" msgid="6736551095997839472">"在横向视图中隐藏字词建议"</string>
@@ -39,20 +39,14 @@
<string name="quick_fixes" msgid="5353213327680897927">"快速纠正"</string>
<string name="quick_fixes_summary" msgid="3405028402510332373">"纠正常见的输入错误"</string>
<string name="show_suggestions" msgid="507074425254289133">"显示建议"</string>
- <string name="show_suggestions_summary" msgid="1989672863935759654">"输入时显示建议的字词"</string>
- <string name="auto_complete" msgid="1103196318775486023">"自动输入"</string>
- <string name="auto_complete_summary" msgid="6113149638718274624">"按空格或标点可自动插入突出显示的字词"</string>
+ <string name="show_suggestions_summary" msgid="1989672863935759654">"输入时启用联想提示"</string>
+ <string name="auto_complete" msgid="1103196318775486023">"自动填写"</string>
+ <string name="auto_complete_summary" msgid="6113149638718274624">"按空格键和标点符号时自动插入突出显示的字词"</string>
<string-array name="prediction_modes">
<item msgid="4870266572388153286">"无"</item>
<item msgid="1669461741568287396">"基本模式"</item>
<item msgid="4894328801530136615">"高级模式"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已保存"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -64,17 +58,17 @@
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
<string name="key_i" msgid="6483655742552255124">"i"</string>
- <string name="tip_long_press" msgid="6101270866284343344">"长按某些键可看到重音符号(例如 ø、ö 等)"</string>
+ <string name="tip_long_press" msgid="6101270866284343344">"按住某个键可看到重音符号(例如 ø、ö 等)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"随时可以通过按后退键 ↶ 关闭键盘"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"访问数字和符号"</string>
<string name="tip_add_to_dictionary" msgid="1487293888469227817">"长按最左侧的字可将其添加到词典中"</string>
<string name="touch_to_continue" msgid="7869803257948414531">"轻触此提示继续 »"</string>
<string name="touch_to_finish" msgid="7990196086480585789">"轻触此处可关闭该提示,然后便可开始输入内容!"</string>
<string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"轻触文本字段即可打开键盘"</b></string>
- <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"长按某些键可看到重音符号"\n"(例如 ø、ö、ô、ó 等)"</b></string>
+ <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"按住某个键可看到重音符号"\n"(例如 ø、ö、ô、ó 等)"</b></string>
<string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"轻触该键可切换到数字和符号输入模式"</b></string>
<string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"再次轻触该键可返回字母输入模式"</b></string>
- <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"长按该键可更改键盘设置,例如自动输入"</b></string>
+ <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"长按该键可更改键盘设置,例如自动填写"</b></string>
<string name="tip_to_start_typing" msgid="7213843601369174313"><b>"试试吧!"</b></string>
<string name="label_go_key" msgid="1635148082137219148">"开始"</string>
<string name="label_next_key" msgid="362972844525672568">"下一步"</string>
@@ -84,13 +78,40 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"语音输入"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"语音输入功能当前还不支持您的语言,您只能输入英语语音。"</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"语音输入是一项试验性的功能,它采用了 Google 的网络语音识别功能。"</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"要关闭语音输入功能,请转至键盘设置。"</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"要使用语音输入,请按麦克风按钮或者在屏幕键盘上滑动手指。"</string>
+ <string name="voice_listening" msgid="467518160751321844">"请开始说话"</string>
+ <string name="voice_working" msgid="6666937792815731889">"正在处理"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"出错,请重试。"</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"无法连接"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"出错,语音过长。"</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"音频问题"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"服务器出错"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"未听到语音"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"未找到匹配项"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"未安装语音搜索"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"提示:"</b>"在键盘上滑动手指可激活语音功能"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"提示:"</b>"稍后,请尝试使用语音输入标点符号,如“句号”、“逗号”或“问号”。"</string>
+ <string name="cancel" msgid="6830980399865683324">"取消"</string>
+ <string name="ok" msgid="7898366843681727667">"确定"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"语音输入"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"语音结束后自动提交"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"搜索或转到下一字段时自动按 Enter。"</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"打开键盘"\n</b></font><font size="3">\n</font>"轻触任意文本字段。"</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"关闭键盘"\n</b></font><font size="3">\n</font>"按“返回”键。"</string>
- <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"长按某些键可开启其他字符选项"\n</b></font><font size="3">\n</font>"访问标点和重音符号。"</string>
+ <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"按住某个键可开启其他字符选项"\n</b></font><font size="3">\n</font>"访问标点和重音符号。"</string>
<string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"键盘设置"\n</b></font><font size="3">\n</font>"长按 "<b>"?123"</b>" 键。"</string>
<string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
<string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"输入法"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 8d93b311a..9603c6b80 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -47,12 +47,6 @@
<item msgid="1669461741568287396">"基本模式"</item>
<item msgid="4894328801530136615">"進階模式"</item>
</string-array>
- <string name="prediction_none" msgid="2472795101338047944">"0"</string>
- <string name="prediction_basic" msgid="8407291081834155558">"1"</string>
- <string name="prediction_full" msgid="3765102052052510268">"2"</string>
- <!-- no translation found for prediction_modes_values:0 (579944677836100459) -->
- <!-- no translation found for prediction_modes_values:1 (7214414132844804570) -->
- <!-- no translation found for prediction_modes_values:2 (6678546276084314171) -->
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string>
<string name="alternates_for_a" msgid="2566516493365324765">"àáâãäåæ"</string>
<string name="alternates_for_e" msgid="3900510936875547555">"èéêë"</string>
@@ -63,7 +57,6 @@
<string name="alternates_for_n" msgid="6257322556221886400">"ñ"</string>
<string name="alternates_for_c" msgid="151699780720639892">"ç"</string>
<string name="alternates_for_y" msgid="1722776806607271199">"ýÿ"</string>
- <string name="key_i" msgid="6483655742552255124">"i"</string>
<string name="tip_long_press" msgid="6101270866284343344">"按住按鍵可查看重音符號 (ø、ö 等)"</string>
<string name="tip_dismiss" msgid="7585579046862204381">"隨時可以透過按後退鍵 ↶ 關閉鍵盤"</string>
<string name="tip_access_symbols" msgid="6344098517525531652">"使用數字和符號"</string>
@@ -84,6 +77,30 @@
<string name="label_phone_key" msgid="4275497665515080551">"123"</string>
<string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
<string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+ <string name="voice_warning_title" msgid="4419354150908395008">"語音輸入"</string>
+ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"語音輸入目前不支援您的語言,但是可以辨識英文。"</string>
+ <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"語音輸入這項實驗功能運用了 Google 的網路語音辨識系統。"</string>
+ <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"請前往鍵盤設定來關閉語音輸入。"</string>
+ <string name="voice_hint_dialog_message" msgid="6892342981545727994">"如要使用語音輸入,按下 [麥克風] 按鈕,或將手指滑過螢幕小鍵盤即可。"</string>
+ <string name="voice_listening" msgid="467518160751321844">"請說話"</string>
+ <string name="voice_working" msgid="6666937792815731889">"辨識中"</string>
+ <!-- no translation found for voice_initializing (661962047129906646) -->
+ <skip />
+ <string name="voice_error" msgid="5140896300312186162">"發生錯誤,請再試一次。"</string>
+ <string name="voice_network_error" msgid="6649556447401862563">"無法連線"</string>
+ <string name="voice_too_much_speech" msgid="5746973620134227376">"錯誤:語音內容過長。"</string>
+ <string name="voice_audio_error" msgid="5072707727016414454">"音訊問題"</string>
+ <string name="voice_server_error" msgid="7807129913977261644">"伺服器錯誤"</string>
+ <string name="voice_speech_timeout" msgid="8461817525075498795">"沒有聽到任何聲音"</string>
+ <string name="voice_no_match" msgid="4285117547030179174">"找不到相符的項目"</string>
+ <string name="voice_not_installed" msgid="5552450909753842415">"未安裝語音搜尋"</string>
+ <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"提示:"</b>"滑過鍵盤即可說話"</string>
+ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"提示:"</b>"下次可嘗試說出標點符號,例如「句號」、「逗號」或「問號」。"</string>
+ <string name="cancel" msgid="6830980399865683324">"取消"</string>
+ <string name="ok" msgid="7898366843681727667">"確定"</string>
+ <string name="enable_voice" msgid="8299503298530853956">"語音輸入"</string>
+ <string name="auto_submit" msgid="9151008027068358518">"說話後自動提交"</string>
+ <string name="auto_submit_summary" msgid="4961875269610384226">"搜尋或前往下一個欄位時自動按下輸入。"</string>
<string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"開啟鍵盤"\n</b></font><font size="3">\n</font>"輕觸任何文字欄位。"</string>
<string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"關閉鍵盤"\n</b></font><font size="3">\n</font>"按下 Back 鍵。"</string>
<string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>\n"輕觸並按住按鍵開啟選項"</b></font><font size="3">\n</font>"輸入標點與輕重音。"</string>
@@ -93,4 +110,7 @@
<string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
<string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
<string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+ <!-- no translation found for language_selection_title (530749890984542339) -->
+ <skip />
+ <string name="inputMethod" msgid="7854532062009028116">"輸入方式"</string>
</resources>
diff --git a/res/values/bools.xml b/res/values/bools.xml
index 3a951b271..ebe2f04e5 100644
--- a/res/values/bools.xml
+++ b/res/values/bools.xml
@@ -23,4 +23,6 @@
<!-- Whether this input method should be used as the default for a locale. Override it
for latin languages. -->
<bool name="im_is_default">false</bool>
+ <!-- Whether or not voice input is enabled by default. -->
+ <bool name="voice_input_default">true</bool>
</resources>
diff --git a/res/values/donottranslate.xml b/res/values/donottranslate.xml
index c6941949e..edf230061 100644
--- a/res/values/donottranslate.xml
+++ b/res/values/donottranslate.xml
@@ -21,7 +21,9 @@
<!-- Symbols that are commonly considered word separators in this language -->
<string name="word_separators">.\u0020,;:!?\n()[]*&amp;@{}/&lt;&gt;_+=|\u0022</string>
<!-- Symbols that are sentence separators, for purposes of making it hug the last sentence. -->
- <string name="sentence_separators">.,;:!?</string>
+ <string name="sentence_separators">.,!?</string>
+ <!-- Symbols that are suggested between words -->
+ <string name="suggested_punctuations">!?,@_</string>
<!-- Accented characters related to "d" -->
<string name="alternates_for_d"></string>
<!-- Accented characters related to "r" -->
@@ -32,6 +34,4 @@
<string name="alternates_for_z"></string>
<!-- Accented characters related to "l" -->
<string name="alternates_for_l"></string>
- <!-- Accented characters related to "g" -->
- <string name="alternates_for_g"></string>
</resources>
diff --git a/res/values/keycodes.xml b/res/values/keycodes.xml
new file mode 100644
index 000000000..8156c0e07
--- /dev/null
+++ b/res/values/keycodes.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2009, 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>
+ <!-- Keycode for F1 (function) key. This one switches between language switch & comma/.com -->
+ <integer name="key_f1">-103</integer>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ec9a8b731..85de32207 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -93,13 +93,13 @@
</string-array>
<!-- Don't translate -->
- <string name="prediction_none" >0</string>
+ <string name="prediction_none" translatable="false">0</string>
<!-- Don't translate -->
- <string name="prediction_basic">1</string>
+ <string name="prediction_basic" translatable="false">1</string>
<!-- Don't translate -->
- <string name="prediction_full" >2</string>
+ <string name="prediction_full" translatable="false">2</string>
- <string-array name="prediction_modes_values">
+ <string-array name="prediction_modes_values" translatable="false">
<item>@string/prediction_none</item>
<item>@string/prediction_basic</item>
<item>@string/prediction_full</item>
@@ -125,10 +125,7 @@
<string name="alternates_for_c">ç</string>
<!-- Accented forms of "y" -->
<string name="alternates_for_y">ýÿ</string>
-
- <!-- Label to display on the "i" key -->
- <string name="key_i">i</string>
-
+
<!-- Tip to long press on keys -->
<string name="tip_long_press">Hold a key down to see accents (ø, ö, etc.)</string>
<!-- Tip to dismiss keyboard -->
@@ -182,6 +179,91 @@
<!-- Label for ALT modifier key. Must be short to fit on key! -->
<string name="label_alt_key">ALT</string>
+ <!-- Voice related labels -->
+
+ <!-- Title of the warning dialog that shows when a user initiates voice input for
+ the first time. -->
+ <string name="voice_warning_title">Voice input</string>
+
+ <!-- Message that gets put at the top of the warning dialog if the user is attempting to use
+ voice input in a currently unsupported locale. Voice input will work for such a user,
+ but it will only recognize them in English. -->
+ <string name="voice_warning_locale_not_supported">Voice input is not currently supported for your language, but does work in English.</string>
+
+ <!-- Message of the warning dialog that shows when a user initiates voice input for
+ the first time, or turns it on in settings. -->
+ <string name="voice_warning_may_not_understand">Voice input is an experimental feature using Google\'s networked speech recognition.</string>
+
+ <!-- An additional part of the warning dialog for voice input that only shows when the user
+ actually initiates voice input, rather than just turning it on in settings. -->
+ <string name="voice_warning_how_to_turn_off">To turn off voice input, go to keyboard settings.</string>
+
+ <!-- Message to show when user clicks the swiping hint (which says
+ "Swipe across keyboard to speak"). Also shown when enabling settings. -->
+ <string name="voice_hint_dialog_message">To use voice input, press the microphone button or slide your finger across the on-screen keyboard.</string>
+
+ <!-- Short message to tell the user the system is ready for them to speak. -->
+ <string name="voice_listening">Speak now</string>
+
+ <!-- Short message shown after the user finishes speaking. -->
+ <string name="voice_working">Working</string>
+
+ <!-- Short message shown before the user should speak. -->
+ <string name="voice_initializing"></string>
+
+ <!-- Short message shown when a generic error occurs. -->
+ <string name="voice_error">Error. Please try again.</string>
+
+ <!-- Short message shown for a network error. -->
+ <string name="voice_network_error">Couldn\'t connect</string>
+
+ <!-- Short message shown for a network error where the utterance was really long,
+ in which case we should suggest that the user speak less. -->
+ <string name="voice_too_much_speech">Error, too much speech.</string>
+
+ <!-- Short message shown for an audio error. -->
+ <string name="voice_audio_error">Audio problem</string>
+
+ <!-- Short message shown for an error with the voice server. -->
+ <string name="voice_server_error">Server error</string>
+
+ <!-- Short message shown when no speech is heard. -->
+ <string name="voice_speech_timeout">No speech heard</string>
+
+ <!-- Short message shown when the server couldn't parse any speech. -->
+ <string name="voice_no_match">No matches found</string>
+
+ <!-- Short message shown when the user initiates voice and voice
+ search is not installed. -->
+ <string name="voice_not_installed">Voice search not installed</string>
+
+ <!-- Short hint shown in candidate view to explain voice input. -->
+ <string name="voice_swipe_hint"><b>Hint:</b> Swipe across keyboard to speak</string>
+
+ <!-- Short hint shown in candidate view to explain that user can speak punctuation. -->
+ <string name="voice_punctuation_hint"><b>Hint:</b> Next time, try speaking punctuation like \"period\", \"comma\", or \"question mark\".</string>
+
+ <!-- Label on button to stop recognition. Must be short to fit on button. -->
+ <string name="cancel">Cancel</string>
+
+ <!-- Label on button when an error occurs -->
+ <string name="ok">OK</string>
+
+ <!-- Preferences item for enabling speech input -->
+ <string name="enable_voice">Voice input</string>
+
+ <!-- Preferences item for speech icon on primary keyboard -->
+ <string name="voice_on_primary">Mic on primary</string>
+
+ <!-- Preferences item summary for speech icon on primary keyboard -->
+ <string name="voice_on_primary_summary">Show the microphone on the primary keyboard</string>
+
+ <!-- Press the "enter" key after the user speaks. Option on settings.-->
+ <string name="auto_submit">Auto submit after voice</string>
+
+ <!-- Press the "enter" key after the user speaks. Summary of option in settings.-->
+ <string name="auto_submit_summary">Automatically press enter when searching or going to the next field.</string>
+
<!-- IME Tutorial screen (ROMAN) --><skip />
<!-- appears above image showing the user to click on a TextView to show the IME -->
<string name="open_the_keyboard"><font size="17"><b>Open the keyboard\n</b></font><font size="3">\n</font>Touch any text field.</string>
@@ -194,7 +276,7 @@
<!-- appears above image showing how to access keyboard settings -->
<string name="keyboard_settings"><font size="17"><b>Keyboard settings\n</b></font><font size="3">\n</font>Touch \u0026 hold the <b>\?123\</b> key.</string>
-
+
<!-- popular web domains for the locale - most popular, displayed on the keyboard -->
<string name="popular_domain_0">".com"</string>
<!-- popular web domains for the locale - item 1, displayed in the popup -->
@@ -205,4 +287,10 @@
<string name="popular_domain_3">".gov"</string>
<!-- popular web domains for the locale - item 4, displayed in the popup -->
<string name="popular_domain_4">".edu"</string>
+
+ <!-- Menu item for launching Input method switcher -->
+ <string name="inputMethod">Input method</string>
+
+ <!-- Title for input language selection screen -->
+ <string name="language_selection_title">Select input languages</string>
</resources>
diff --git a/res/xml-de/kbd_qwerty.xml b/res/xml-de/kbd_qwerty.xml
index 56113e217..4e57c6067 100755
--- a/res/xml-de/kbd_qwerty.xml
+++ b/res/xml-de/kbd_qwerty.xml
@@ -96,11 +96,12 @@
</Row>
<Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
- <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="," android:keyWidth="10%p" />
+ <Key android:codes="@integer/key_f1"
+ android:keyWidth="10%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
android:keyWidth="40%p" android:isRepeatable="true"/>
@@ -116,36 +117,35 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="/" android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
<Key android:keyLabel="@string/popular_domain_0"
android:keyOutputText="@string/popular_domain_0"
android:popupKeyboard="@xml/popup_domains"
- android:keyWidth="15%p"/>
- <Key android:keyLabel="/" android:keyWidth="15%p"/>
- <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="15%p" android:isRepeatable="true"/>
+ android:keyWidth="20%p"/>
<Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
- android:keyWidth="15%p"/>
+ android:keyWidth="10%p"/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
<Row android:keyboardMode="@+id/mode_email" android:rowEdgeFlags="bottom">
- <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="\@" android:keyWidth="15%p"/>
+ <Key android:keyLabel="\@"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
<Key android:keyLabel="@string/popular_domain_0"
android:keyOutputText="@string/popular_domain_0"
android:popupKeyboard="@xml/popup_domains"
- android:keyWidth="15%p"/>
- <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="15%p" android:isRepeatable="true"/>
- <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
- android:keyWidth="15%p"/>
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
@@ -156,7 +156,8 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="," android:keyWidth="10%p"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
android:keyWidth="40%p" android:isRepeatable="true"/>
@@ -165,6 +166,24 @@
<Key android:keyLabel=":-)" android:keyOutputText=":-) "
android:popupKeyboard="@xml/popup_smileys"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+ <Row android:keyboardMode="@+id/mode_webentry" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:codes="9" android:keyIcon="@drawable/sym_keyboard_tab"
+ android:iconPreview="@drawable/sym_keyboard_feedback_tab"
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
</Keyboard>
diff --git a/res/xml-fr/kbd_qwerty.xml b/res/xml-fr/kbd_qwerty.xml
index d47042ea7..1b20c0438 100644
--- a/res/xml-fr/kbd_qwerty.xml
+++ b/res/xml-fr/kbd_qwerty.xml
@@ -100,54 +100,54 @@
<Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
<Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
android:popupKeyboard="@xml/kbd_popup_template"
- android:popupCharacters=""
+ android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="," android:keyWidth="10%p" />
- <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
android:keyWidth="40%p" android:isRepeatable="true"/>
<Key android:codes="46" android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
android:keyWidth="10%p"/>
- <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
<Row android:keyboardMode="@+id/mode_url" android:rowEdgeFlags="bottom">
- <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
android:popupKeyboard="@xml/kbd_popup_template"
- android:popupCharacters=""
+ android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="/" android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
<Key android:keyLabel="@string/popular_domain_0"
android:keyOutputText="@string/popular_domain_0"
android:popupKeyboard="@xml/popup_domains"
- android:keyWidth="15%p"/>
- <Key android:keyLabel="/" android:keyWidth="15%p"/>
- <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="15%p" android:isRepeatable="true"/>
- <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
- android:keyWidth="15%p"/>
- <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
+ android:keyWidth="10%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
<Row android:keyboardMode="@+id/mode_email" android:rowEdgeFlags="bottom">
- <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
android:popupKeyboard="@xml/kbd_popup_template"
- android:popupCharacters=""
+ android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="\@" android:keyWidth="15%p"/>
+ <Key android:keyLabel="\@"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
<Key android:keyLabel="@string/popular_domain_0"
android:keyOutputText="@string/popular_domain_0"
android:popupKeyboard="@xml/popup_domains"
- android:keyWidth="15%p"/>
- <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="15%p" android:isRepeatable="true"/>
- <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
- android:keyWidth="15%p"/>
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
@@ -156,17 +156,38 @@
<Row android:keyboardMode="@+id/mode_im" android:rowEdgeFlags="bottom">
<Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
android:popupKeyboard="@xml/kbd_popup_template"
- android:popupCharacters=""
+ android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="," android:keyWidth="10%p"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
android:keyWidth="40%p" android:isRepeatable="true"/>
- <Key android:codes="46" android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
+ <Key android:codes="46" android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
android:keyWidth="10%p"/>
<Key android:keyLabel=":-)" android:keyOutputText=":-) "
android:popupKeyboard="@xml/popup_smileys"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
+
+ <Row android:keyboardMode="@+id/mode_webentry" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:codes="9" android:keyIcon="@drawable/sym_keyboard_tab"
+ android:iconPreview="@drawable/sym_keyboard_feedback_tab"
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
</Keyboard>
- \ No newline at end of file
+
diff --git a/res/xml-ru/kbd_qwerty.xml b/res/xml-ru/kbd_qwerty.xml
new file mode 100755
index 000000000..45d355b0f
--- /dev/null
+++ b/res/xml-ru/kbd_qwerty.xml
@@ -0,0 +1,174 @@
+<?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.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="9.09%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row>
+ <Key android:keyLabel="й"
+ android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="ц"/>
+ <Key android:keyLabel="у"/>
+ <Key android:keyLabel="к"/>
+ <Key android:keyLabel="е"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="ё" />
+ <Key android:keyLabel="н"/>
+ <Key android:keyLabel="г"/>
+ <Key android:keyLabel="ш"/>
+ <Key android:keyLabel="щ"/>
+ <Key android:keyLabel="з"/>
+ <Key android:keyLabel="х"
+ android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:keyLabel="ф"
+ android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="ы"/>
+ <Key android:keyLabel="в"/>
+ <Key android:keyLabel="а"/>
+ <Key android:keyLabel="п"/>
+ <Key android:keyLabel="р"/>
+ <Key android:keyLabel="о"/>
+ <Key android:keyLabel="л"/>
+ <Key android:keyLabel="д"/>
+ <Key android:keyLabel="ж"/>
+ <Key android:keyLabel="э"
+ android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row android:keyWidth="8.5%p">
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="11.75%p" android:isModifier="true"
+ android:iconPreview="@drawable/sym_keyboard_feedback_shift"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="я"/>
+ <Key android:keyLabel="ч"/>
+ <Key android:keyLabel="с"/>
+ <Key android:keyLabel="м"/>
+ <Key android:keyLabel="и"/>
+ <Key android:keyLabel="т"/>
+ <Key android:keyLabel="ь"/>
+ <Key android:keyLabel="б"/>
+ <Key android:keyLabel="ю"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="11.75%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="40%p" android:isRepeatable="true"/>
+ <Key android:codes="46" android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
+ android:keyWidth="10%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_url" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="/" android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="@string/popular_domain_0"
+ android:keyOutputText="@string/popular_domain_0"
+ android:popupKeyboard="@xml/popup_domains"
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
+ android:keyWidth="10%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_email" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="\@" android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="@string/popular_domain_0"
+ android:keyOutputText="@string/popular_domain_0"
+ android:popupKeyboard="@xml/popup_domains"
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_im" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="40%p" android:isRepeatable="true"/>
+ <Key android:codes="46" android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
+ android:keyWidth="10%p"/>
+ <Key android:keyLabel=":-)" android:keyOutputText=":-) "
+ android:popupKeyboard="@xml/popup_smileys"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_webentry" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_globe"
+ android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:codes="9" android:keyIcon="@drawable/sym_keyboard_tab"
+ android:iconPreview="@drawable/sym_keyboard_feedback_tab"
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+</Keyboard>
+
diff --git a/res/xml/kbd_extension.xml b/res/xml/kbd_extension.xml
new file mode 100755
index 000000000..c64f666d0
--- /dev/null
+++ b/res/xml/kbd_extension.xml
@@ -0,0 +1,61 @@
+<?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.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row android:rowEdgeFlags="top">
+ <Key android:keyLabel="!" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="\@"/>
+ <Key android:keyLabel="\#"/>
+ <Key android:keyLabel="&amp;"/>
+ <Key android:keyLabel="-"/>
+ <Key android:keyLabel="\'"/>
+ <Key android:keyLabel=":"/>
+ <Key android:keyLabel="&quot;"/>
+ <Key android:keyLabel="/"/>
+ <Key android:keyLabel="\?" android:keyEdgeFlags="right"
+ />
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom">
+ <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"
+ />
+ <Key android:codes="50" android:keyLabel="2"
+ />
+ <Key android:codes="51" android:keyLabel="3"
+ />
+ <Key android:codes="52" android:keyLabel="4"
+ />
+ <Key android:codes="53" android:keyLabel="5"
+ />
+ <Key android:codes="54" android:keyLabel="6"/>
+ <Key android:codes="55" android:keyLabel="7"
+ />
+ <Key android:codes="56" android:keyLabel="8"/>
+ <Key android:codes="57" android:keyLabel="9"/>
+ <Key android:codes="48" android:keyLabel="0"
+ android:keyEdgeFlags="right"/>
+ </Row>
+</Keyboard>
diff --git a/res/xml/kbd_qwerty.xml b/res/xml/kbd_qwerty.xml
index 0493b9932..4aa476136 100755
--- a/res/xml/kbd_qwerty.xml
+++ b/res/xml/kbd_qwerty.xml
@@ -46,7 +46,7 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="@string/alternates_for_u"
/>
- <Key android:keyLabel="@string/key_i"
+ <Key android:codes="105" android:keyLabel="i"
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="@string/alternates_for_i"
/>
@@ -70,14 +70,11 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="@string/alternates_for_d"/>
<Key android:codes="102" android:keyLabel="f"/>
- <Key android:codes="103" android:keyLabel="g"
- android:popupKeyboard="@xml/kbd_popup_template"
- android:popupCharacters="@string/alternates_for_g"/>
- />
+ <Key android:codes="103" android:keyLabel="g"/>
<Key android:codes="104" android:keyLabel="h"/>
<Key android:codes="106" android:keyLabel="j"/>
<Key android:codes="107" android:keyLabel="k"/>
- <Key android:codes="108" android:keyLabel="l"
+ <Key android:codes="108" android:keyLabel="l"
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="@string/alternates_for_l"
android:keyEdgeFlags="right"/>
@@ -114,7 +111,9 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="," android:keyWidth="10%p" />
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_mic"
+ android:iconPreview="@drawable/sym_keyboard_feedback_mic"
+ android:keyWidth="10%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
android:keyWidth="40%p" android:isRepeatable="true"/>
@@ -130,16 +129,16 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="/" android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
<Key android:keyLabel="@string/popular_domain_0"
android:keyOutputText="@string/popular_domain_0"
android:popupKeyboard="@xml/popup_domains"
- android:keyWidth="15%p"/>
- <Key android:keyLabel="/" android:keyWidth="15%p"/>
- <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="15%p" android:isRepeatable="true"/>
+ android:keyWidth="20%p"/>
<Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
- android:keyWidth="15%p"/>
+ android:keyWidth="10%p"/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
@@ -150,16 +149,15 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="\@" android:keyWidth="15%p"/>
+ <Key android:keyLabel="\@"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
<Key android:keyLabel="@string/popular_domain_0"
android:keyOutputText="@string/popular_domain_0"
android:popupKeyboard="@xml/popup_domains"
- android:keyWidth="15%p"/>
- <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="15%p" android:isRepeatable="true"/>
- <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"
- android:keyWidth="15%p"/>
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
@@ -170,7 +168,9 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="," android:keyWidth="10%p"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_mic"
+ android:iconPreview="@drawable/sym_keyboard_feedback_mic"
+ android:keyWidth="10%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
android:keyWidth="40%p" android:isRepeatable="true"/>
@@ -180,5 +180,26 @@
android:popupKeyboard="@xml/popup_smileys"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
+
+ <Row android:keyboardMode="@+id/mode_webentry" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/label_symbol_key"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="_"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="@integer/key_f1" android:keyIcon="@drawable/sym_keyboard_mic"
+ android:iconPreview="@drawable/sym_keyboard_feedback_mic"
+ android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:codes="9" android:keyIcon="@drawable/sym_keyboard_tab"
+ android:iconPreview="@drawable/sym_keyboard_feedback_tab"
+ android:keyWidth="20%p"/>
+ <Key android:keyLabel="." android:popupKeyboard="@xml/popup_punctuation"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
</Keyboard>
-
+
diff --git a/res/xml/kbd_symbols.xml b/res/xml/kbd_symbols.xml
index f3b8833dc..067932b3f 100755
--- a/res/xml/kbd_symbols.xml
+++ b/res/xml/kbd_symbols.xml
@@ -73,7 +73,7 @@
<Key android:codes="38" android:keyLabel="&amp;"/>
<Key android:codes="42" android:keyLabel="*"
android:popupKeyboard="@xml/kbd_popup_template"
- android:popupCharacters="†‡"
+ android:popupCharacters="†‡★"
/>
<Key android:codes="45" android:keyLabel="-"
android:popupKeyboard="@xml/kbd_popup_template"
@@ -105,7 +105,10 @@
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="“”«»˝"
/>
- <Key android:codes="39" android:keyLabel="\'"/>
+ <Key android:codes="39" android:keyLabel="\'"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="‘’"
+ />
<Key android:codes="58" android:keyLabel=":"/>
<Key android:codes="59" android:keyLabel=";"/>
<Key android:codes="47" android:keyLabel="/" />
@@ -117,16 +120,13 @@
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
android:isRepeatable="true"/>
</Row>
-
+
<Row android:rowEdgeFlags="bottom">
<Key android:codes="-2" android:keyLabel="@string/label_alpha_key"
android:popupKeyboard="@xml/kbd_popup_template"
android:popupCharacters="_"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
- <Key android:keyLabel="," android:keyWidth="10%p"
- android:popupKeyboard="@xml/kbd_popup_template"
- android:popupCharacters="‚„"
- />
+ <Key android:codes="@integer/key_f1" android:keyWidth="10%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:keyWidth="40%p"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
@@ -136,4 +136,4 @@
android:iconPreview="@drawable/sym_keyboard_feedback_return"
/>
</Row>
-</Keyboard> \ No newline at end of file
+</Keyboard>
diff --git a/res/xml/kbd_symbols_shift.xml b/res/xml/kbd_symbols_shift.xml
index 56428a3ad..d83594a24 100755
--- a/res/xml/kbd_symbols_shift.xml
+++ b/res/xml/kbd_symbols_shift.xml
@@ -29,7 +29,10 @@
<Key android:keyLabel="~" android:keyEdgeFlags="left"/>
<Key android:keyLabel="`"/>
<Key android:keyLabel="|"/>
- <Key android:keyLabel="•"/>
+ <Key android:keyLabel="•"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="♪♥♠♦♣"
+ />
<Key android:keyLabel="√"/>
<Key android:keyLabel="π"/>
<Key android:keyLabel="÷"/>
@@ -44,7 +47,10 @@
<Key android:keyLabel="¢"/>
<Key android:keyLabel="€"/>
<Key android:keyLabel="°"/>
- <Key android:keyLabel="^"/>
+ <Key android:keyLabel="^"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="↑↓←→"
+ />
<Key android:keyLabel="_"/>
<Key android:keyLabel="="
android:popupKeyboard="@xml/kbd_popup_template"
@@ -61,7 +67,10 @@
<Key android:keyLabel="™"/>
<Key android:keyLabel="®"/>
<Key android:keyLabel="©"/>
- <Key android:keyLabel="¶"/>
+ <Key android:keyLabel="¶"
+ android:popupKeyboard="@xml/kbd_popup_template"
+ android:popupCharacters="§"
+ />
<Key android:keyLabel="\\"/>
<Key android:keyLabel="&lt;"
android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/res/xml/language_prefs.xml b/res/xml/language_prefs.xml
new file mode 100644
index 000000000..b7a4c07db
--- /dev/null
+++ b/res/xml/language_prefs.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/language_selection_title">
+</PreferenceScreen>
diff --git a/res/xml/method.xml b/res/xml/method.xml
index e5654e96d..195691b7b 100644
--- a/res/xml/method.xml
+++ b/res/xml/method.xml
@@ -22,5 +22,5 @@
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.android.inputmethod.latin.LatinIMESettings"
- android:isDefault="@bool/im_is_default"
+ android:isDefault="true"
/>
diff --git a/res/xml/prefs.xml b/res/xml/prefs.xml
index 2fc82aadb..4792c43cf 100644
--- a/res/xml/prefs.xml
+++ b/res/xml/prefs.xml
@@ -37,6 +37,30 @@
android:defaultValue="true"
/>
+ <CheckBoxPreference
+ android:key="enable_voice_input"
+ android:title="@string/enable_voice"
+ android:persistent="false"
+ android:defaultValue="@bool/voice_input_default"
+ />
+
+ <CheckBoxPreference
+ android:key="voice_on_main"
+ android:title="@string/voice_on_primary"
+ android:summary="@string/voice_on_primary_summary"
+ android:persistent="true"
+ android:dependency="enable_voice_input"
+ android:defaultValue="@bool/voice_input_default"
+ />
+
+ <PreferenceScreen
+ android:title="@string/language_selection_title">
+ <intent
+ android:action="android.intent.action.MAIN"
+ android:targetPackage="com.android.inputmethod.latin"
+ android:targetClass="com.android.inputmethod.latin.InputLanguageSelection" />
+ </PreferenceScreen>
+
<PreferenceCategory
android:title="@string/prediction_category"
android:key="prediction_settings">
diff --git a/src/com/android/inputmethod/latin/BinaryDictionary.java b/src/com/android/inputmethod/latin/BinaryDictionary.java
index e7470a8fc..68d8b740c 100644
--- a/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -35,8 +35,8 @@ public class BinaryDictionary extends Dictionary {
private static final boolean ENABLE_MISSED_CHARACTERS = true;
private int mNativeDict;
+ private int mDictLength; // This value is set from native code, don't change the name!!!!
private int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES];
- private WordCallback mWordCallback;
private char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS];
private int[] mFrequencies = new int[MAX_WORDS];
@@ -75,7 +75,6 @@ public class BinaryDictionary extends Dictionary {
@Override
public void getWords(final WordComposer codes, final WordCallback callback) {
- mWordCallback = callback;
final int codesSize = codes.size();
// Wont deal with really long words.
if (codesSize > MAX_WORD_LENGTH - 1) return;
@@ -123,12 +122,18 @@ public class BinaryDictionary extends Dictionary {
@Override
public boolean isValidWord(CharSequence word) {
if (word == null) return false;
- char[] chars = word.toString().toLowerCase().toCharArray();
+ char[] chars = word.toString().toCharArray();
return isValidWordNative(mNativeDict, chars, chars.length);
}
+ public int getSize() {
+ return mDictLength; // This value is initialized on the call to openNative()
+ }
+
+ @Override
public synchronized void close() {
if (mNativeDict != 0) {
+ System.err.println("Closing BinaryDictionary");
closeNative(mNativeDict);
mNativeDict = 0;
}
diff --git a/src/com/android/inputmethod/latin/CandidateView.java b/src/com/android/inputmethod/latin/CandidateView.java
index f397363c3..0b6b89e6b 100755
--- a/src/com/android/inputmethod/latin/CandidateView.java
+++ b/src/com/android/inputmethod/latin/CandidateView.java
@@ -26,6 +26,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
+import android.graphics.Paint.Align;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
@@ -82,7 +83,9 @@ public class CandidateView extends View {
private int mDescent;
private boolean mScrolled;
private int mTargetScrollX;
-
+
+ private int mMinTouchableWidth;
+
private int mTotalWidth;
private GestureDetector mGestureDetector;
@@ -113,7 +116,7 @@ public class CandidateView extends View {
public CandidateView(Context context, AttributeSet attrs) {
super(context, attrs);
mSelectionHighlight = context.getResources().getDrawable(
- com.android.internal.R.drawable.list_selector_background_pressed);
+ R.drawable.list_selector_background_pressed);
LayoutInflater inflate =
(LayoutInflater) context
@@ -133,13 +136,16 @@ public class CandidateView extends View {
mPaint.setAntiAlias(true);
mPaint.setTextSize(mPreviewText.getTextSize());
mPaint.setStrokeWidth(0);
+ mPaint.setTextAlign(Align.CENTER);
mDescent = (int) mPaint.descent();
+ // 80 pixels for a 160dpi device would mean half an inch
+ mMinTouchableWidth = (int) (getResources().getDisplayMetrics().density * 50);
mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent me) {
if (mSuggestions.size() > 0) {
- if (me.getX() + mScrollX < mWordWidth[0] && mScrollX < 10) {
+ if (me.getX() + getScrollX() < mWordWidth[0] && getScrollX() < 10) {
longPressFirstWord();
}
}
@@ -150,14 +156,16 @@ public class CandidateView extends View {
float distanceX, float distanceY) {
final int width = getWidth();
mScrolled = true;
- mScrollX += (int) distanceX;
- if (mScrollX < 0) {
- mScrollX = 0;
+ int scrollX = getScrollX();
+ scrollX += (int) distanceX;
+ if (scrollX < 0) {
+ scrollX = 0;
}
- if (distanceX > 0 && mScrollX + width > mTotalWidth) {
- mScrollX -= (int) distanceX;
+ if (distanceX > 0 && scrollX + width > mTotalWidth) {
+ scrollX -= (int) distanceX;
}
- mTargetScrollX = mScrollX;
+ mTargetScrollX = scrollX;
+ scrollTo(scrollX, getScrollY());
hidePreview();
invalidate();
return true;
@@ -167,7 +175,7 @@ public class CandidateView extends View {
setWillNotDraw(false);
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
- mScrollX = 0;
+ scrollTo(0, getScrollY());
}
/**
@@ -201,7 +209,7 @@ public class CandidateView extends View {
if (getBackground() != null) {
getBackground().getPadding(mBgPadding);
}
- mDivider.setBounds(0, mBgPadding.top, mDivider.getIntrinsicWidth(),
+ mDivider.setBounds(0, 0, mDivider.getIntrinsicWidth(),
mDivider.getIntrinsicHeight());
}
int x = 0;
@@ -210,7 +218,7 @@ public class CandidateView extends View {
final Rect bgPadding = mBgPadding;
final Paint paint = mPaint;
final int touchX = mTouchX;
- final int scrollX = mScrollX;
+ final int scrollX = getScrollX();
final boolean scrolled = mScrolled;
final boolean typedWordValid = mTypedWordValid;
final int y = (int) (height + mPaint.getTextSize() - mDescent) / 2;
@@ -231,7 +239,7 @@ public class CandidateView extends View {
wordWidth = mWordWidth[i];
} else {
float textWidth = paint.measureText(suggestion, 0, suggestion.length());
- wordWidth = (int) textWidth + X_GAP * 2;
+ wordWidth = Math.max(mMinTouchableWidth, (int) textWidth + X_GAP * 2);
mWordWidth[i] = wordWidth;
}
@@ -251,7 +259,7 @@ public class CandidateView extends View {
}
if (canvas != null) {
- canvas.drawText(suggestion, 0, suggestion.length(), x + X_GAP, y, paint);
+ canvas.drawText(suggestion, 0, suggestion.length(), x + wordWidth / 2, y, paint);
paint.setColor(mColorOther);
canvas.translate(x + wordWidth, 0);
mDivider.draw(canvas);
@@ -261,23 +269,30 @@ public class CandidateView extends View {
x += wordWidth;
}
mTotalWidth = x;
- if (mTargetScrollX != mScrollX) {
+ if (mTargetScrollX != scrollX) {
scrollToTarget();
}
}
private void scrollToTarget() {
- if (mTargetScrollX > mScrollX) {
- mScrollX += SCROLL_PIXELS;
- if (mScrollX >= mTargetScrollX) {
- mScrollX = mTargetScrollX;
+ int scrollX = getScrollX();
+ if (mTargetScrollX > scrollX) {
+ scrollX += SCROLL_PIXELS;
+ if (scrollX >= mTargetScrollX) {
+ scrollX = mTargetScrollX;
+ scrollTo(scrollX, getScrollY());
requestLayout();
+ } else {
+ scrollTo(scrollX, getScrollY());
}
} else {
- mScrollX -= SCROLL_PIXELS;
- if (mScrollX <= mTargetScrollX) {
- mScrollX = mTargetScrollX;
+ scrollX -= SCROLL_PIXELS;
+ if (scrollX <= mTargetScrollX) {
+ scrollX = mTargetScrollX;
+ scrollTo(scrollX, getScrollY());
requestLayout();
+ } else {
+ scrollTo(scrollX, getScrollY());
}
}
invalidate();
@@ -291,7 +306,7 @@ public class CandidateView extends View {
}
mShowingCompletions = completions;
mTypedWordValid = typedWordValid;
- mScrollX = 0;
+ scrollTo(0, getScrollY());
mTargetScrollX = 0;
mHaveMinimalSuggestion = haveMinimalSuggestion;
// Compute the total width
@@ -305,8 +320,8 @@ public class CandidateView extends View {
final int count = mSuggestions.size();
int firstItem = 0; // Actually just before the first item, if at the boundary
while (i < count) {
- if (mWordX[i] < mScrollX
- && mWordX[i] + mWordWidth[i] >= mScrollX - 1) {
+ if (mWordX[i] < getScrollX()
+ && mWordX[i] + mWordWidth[i] >= getScrollX() - 1) {
firstItem = i;
break;
}
@@ -319,9 +334,10 @@ public class CandidateView extends View {
public void scrollNext() {
int i = 0;
- int targetX = mScrollX;
+ int scrollX = getScrollX();
+ int targetX = scrollX;
final int count = mSuggestions.size();
- int rightEdge = mScrollX + getWidth();
+ int rightEdge = scrollX + getWidth();
while (i < count) {
if (mWordX[i] <= rightEdge &&
mWordX[i] + mWordWidth[i] >= rightEdge) {
@@ -334,7 +350,7 @@ public class CandidateView extends View {
}
private void updateScrollPosition(int targetX) {
- if (targetX != mScrollX) {
+ if (targetX != getScrollX()) {
// TODO: Animate
mTargetScrollX = targetX;
requestLayout();
@@ -452,7 +468,8 @@ public class CandidateView extends View {
+ mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight();
final int popupHeight = mPreviewText.getMeasuredHeight();
//mPreviewText.setVisibility(INVISIBLE);
- mPopupPreviewX = mWordX[wordIndex] - mPreviewText.getPaddingLeft() - mScrollX;
+ mPopupPreviewX = mWordX[wordIndex] - mPreviewText.getPaddingLeft() - getScrollX()
+ + (mWordWidth[wordIndex] - wordWidth) / 2;
mPopupPreviewY = - popupHeight;
mHandler.removeMessages(MSG_REMOVE_PREVIEW);
int [] offsetInWindow = new int[2];
@@ -478,6 +495,7 @@ public class CandidateView extends View {
private void longPressFirstWord() {
CharSequence word = mSuggestions.get(0);
+ if (word.length() < 2) return;
if (mService.addWordToDictionary(word.toString())) {
showPreview(0, getContext().getResources().getString(R.string.added_word, word));
}
diff --git a/src/com/android/inputmethod/latin/Dictionary.java b/src/com/android/inputmethod/latin/Dictionary.java
index fdf34264a..6c1c856e7 100644
--- a/src/com/android/inputmethod/latin/Dictionary.java
+++ b/src/com/android/inputmethod/latin/Dictionary.java
@@ -86,4 +86,9 @@ abstract public class Dictionary {
return true;
}
+ /**
+ * Override to clean up any resources.
+ */
+ public void close() {
+ }
}
diff --git a/src/com/android/inputmethod/latin/ExpandableDictionary.java b/src/com/android/inputmethod/latin/ExpandableDictionary.java
index a136ee7f4..1589168ee 100644
--- a/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -105,8 +105,8 @@ public class ExpandableDictionary extends Dictionary {
if (wordLength == depth + 1) {
// Terminate this word
childNode.terminal = true;
- childNode.frequency += frequency; // If there are multiple similar words
- if (childNode.frequency > 256) childNode.frequency = 256;
+ childNode.frequency = Math.max(frequency, childNode.frequency);
+ if (childNode.frequency > 255) childNode.frequency = 255;
return;
}
if (childNode.children == null) {
diff --git a/src/com/android/inputmethod/latin/Hints.java b/src/com/android/inputmethod/latin/Hints.java
new file mode 100644
index 000000000..689c8d852
--- /dev/null
+++ b/src/com/android/inputmethod/latin/Hints.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import com.android.inputmethod.voice.SettingsUtil;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.view.inputmethod.InputConnection;
+
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Logic to determine when to display hints on usage to the user.
+ */
+public class Hints {
+ public interface Display {
+ public void showHint(int viewResource);
+ }
+
+ private static final String TAG = "Hints";
+ private static final String PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN =
+ "voice_hint_num_unique_days_shown";
+ private static final String PREF_VOICE_HINT_LAST_TIME_SHOWN =
+ "voice_hint_last_time_shown";
+ private static final String PREF_VOICE_INPUT_LAST_TIME_USED =
+ "voice_input_last_time_used";
+ private static final String PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT =
+ "voice_punctuation_hint_view_count";
+ private static final int DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW = 7;
+ private static final int DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS = 7;
+
+ private Context mContext;
+ private Display mDisplay;
+ private boolean mVoiceResultContainedPunctuation;
+ private int mSwipeHintMaxDaysToShow;
+ private int mPunctuationHintMaxDisplays;
+
+ // Only show punctuation hint if voice result did not contain punctuation.
+ static final Map<CharSequence, String> SPEAKABLE_PUNCTUATION
+ = new HashMap<CharSequence, String>();
+ static {
+ SPEAKABLE_PUNCTUATION.put(",", "comma");
+ SPEAKABLE_PUNCTUATION.put(".", "period");
+ SPEAKABLE_PUNCTUATION.put("?", "question mark");
+ }
+
+ public Hints(Context context, Display display) {
+ mContext = context;
+ mDisplay = display;
+
+ ContentResolver cr = mContext.getContentResolver();
+ mSwipeHintMaxDaysToShow = SettingsUtil.getSettingsInt(
+ cr,
+ SettingsUtil.LATIN_IME_VOICE_INPUT_SWIPE_HINT_MAX_DAYS,
+ DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW);
+ mPunctuationHintMaxDisplays = SettingsUtil.getSettingsInt(
+ cr,
+ SettingsUtil.LATIN_IME_VOICE_INPUT_PUNCTUATION_HINT_MAX_DISPLAYS,
+ DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS);
+ }
+
+ public boolean showSwipeHintIfNecessary(boolean fieldRecommended) {
+ if (fieldRecommended && shouldShowSwipeHint()) {
+ showHint(R.layout.voice_swipe_hint);
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean showPunctuationHintIfNecessary(InputConnection ic) {
+ if (!mVoiceResultContainedPunctuation
+ && ic != null
+ && getAndIncrementPref(PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT)
+ < mPunctuationHintMaxDisplays) {
+ CharSequence charBeforeCursor = ic.getTextBeforeCursor(1, 0);
+ if (SPEAKABLE_PUNCTUATION.containsKey(charBeforeCursor)) {
+ showHint(R.layout.voice_punctuation_hint);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void registerVoiceResult(String text) {
+ // Update the current time as the last time voice input was used.
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+ editor.putLong(PREF_VOICE_INPUT_LAST_TIME_USED, System.currentTimeMillis());
+ editor.commit();
+
+ mVoiceResultContainedPunctuation = false;
+ for (CharSequence s : SPEAKABLE_PUNCTUATION.keySet()) {
+ if (text.indexOf(s.toString()) >= 0) {
+ mVoiceResultContainedPunctuation = true;
+ break;
+ }
+ }
+ }
+
+ private boolean shouldShowSwipeHint() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+
+ int numUniqueDaysShown = sp.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
+
+ // If we've already shown the hint for enough days, we'll return false.
+ if (numUniqueDaysShown < mSwipeHintMaxDaysToShow) {
+
+ long lastTimeVoiceWasUsed = sp.getLong(PREF_VOICE_INPUT_LAST_TIME_USED, 0);
+
+ // If the user has used voice today, we'll return false. (We don't show the hint on
+ // any day that the user has already used voice.)
+ if (!isFromToday(lastTimeVoiceWasUsed)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether the provided time is from some time today (i.e., this day, month,
+ * and year).
+ */
+ private boolean isFromToday(long timeInMillis) {
+ if (timeInMillis == 0) return false;
+
+ Calendar today = Calendar.getInstance();
+ today.setTimeInMillis(System.currentTimeMillis());
+
+ Calendar timestamp = Calendar.getInstance();
+ timestamp.setTimeInMillis(timeInMillis);
+
+ return (today.get(Calendar.YEAR) == timestamp.get(Calendar.YEAR) &&
+ today.get(Calendar.DAY_OF_MONTH) == timestamp.get(Calendar.DAY_OF_MONTH) &&
+ today.get(Calendar.MONTH) == timestamp.get(Calendar.MONTH));
+ }
+
+ private void showHint(int hintViewResource) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+
+ int numUniqueDaysShown = sp.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
+ long lastTimeHintWasShown = sp.getLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, 0);
+
+ // If this is the first time the hint is being shown today, increase the saved values
+ // to represent that. We don't need to increase the last time the hint was shown unless
+ // it is a different day from the current value.
+ if (!isFromToday(lastTimeHintWasShown)) {
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, numUniqueDaysShown + 1);
+ editor.putLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, System.currentTimeMillis());
+ editor.commit();
+ }
+
+ if (mDisplay != null) {
+ mDisplay.showHint(hintViewResource);
+ }
+ }
+
+ private int getAndIncrementPref(String pref) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+ int value = sp.getInt(pref, 0);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putInt(pref, value + 1);
+ editor.commit();
+ return value;
+ }
+}
diff --git a/src/com/android/inputmethod/latin/InputLanguageSelection.java b/src/com/android/inputmethod/latin/InputLanguageSelection.java
new file mode 100644
index 000000000..47ace7a6f
--- /dev/null
+++ b/src/com/android/inputmethod/latin/InputLanguageSelection.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+public class InputLanguageSelection extends PreferenceActivity {
+
+ private String mSelectedLanguages;
+ private ArrayList<Loc> mAvailableLanguages = new ArrayList<Loc>();
+
+ private static class Loc implements Comparable {
+ static Collator sCollator = Collator.getInstance();
+
+ String label;
+ Locale locale;
+
+ public Loc(String label, Locale locale) {
+ this.label = label;
+ this.locale = locale;
+ }
+
+ @Override
+ public String toString() {
+ return this.label;
+ }
+
+ public int compareTo(Object o) {
+ return sCollator.compare(this.label, ((Loc) o).label);
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.language_prefs);
+ // Get the settings preferences
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ mSelectedLanguages = sp.getString(LatinIME.PREF_SELECTED_LANGUAGES, "");
+ String[] languageList = mSelectedLanguages.split(",");
+ mAvailableLanguages = getUniqueLocales();
+ PreferenceGroup parent = getPreferenceScreen();
+ for (int i = 0; i < mAvailableLanguages.size(); i++) {
+ CheckBoxPreference pref = new CheckBoxPreference(this);
+ Locale locale = mAvailableLanguages.get(i).locale;
+ pref.setTitle(toTitleCase(locale.getDisplayName(locale)));
+ boolean checked = isLocaleIn(locale, languageList);
+ pref.setChecked(checked);
+ parent.addPreference(pref);
+ }
+ }
+
+ private boolean isLocaleIn(Locale locale, String[] list) {
+ String lang = get5Code(locale);
+ for (int i = 0; i < list.length; i++) {
+ if (lang.equalsIgnoreCase(list[i])) return true;
+ }
+ // If it matches the current locale
+ Locale displayLocale = getResources().getConfiguration().locale;
+ if (lang.equalsIgnoreCase(get5Code(displayLocale))) {
+ return true;
+ }
+ return false;
+ }
+
+ private String get5Code(Locale locale) {
+ return locale.getLanguage() + "_" + locale.getCountry();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ // Save the selected languages
+ String checkedLanguages = "";
+ PreferenceGroup parent = getPreferenceScreen();
+ int count = parent.getPreferenceCount();
+ for (int i = 0; i < count; i++) {
+ CheckBoxPreference pref = (CheckBoxPreference) parent.getPreference(i);
+ if (pref.isChecked()) {
+ Locale locale = mAvailableLanguages.get(i).locale;
+ checkedLanguages += get5Code(locale) + ",";
+ }
+ }
+ if (checkedLanguages.length() < 1) checkedLanguages = null; // Save null
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ Editor editor = sp.edit();
+ editor.putString(LatinIME.PREF_SELECTED_LANGUAGES, checkedLanguages);
+ editor.commit();
+ }
+
+ ArrayList<Loc> getUniqueLocales() {
+ String[] locales = getAssets().getLocales();
+ Arrays.sort(locales);
+ ArrayList<Loc> uniqueLocales = new ArrayList<Loc>();
+
+ final int origSize = locales.length;
+ Loc[] preprocess = new Loc[origSize];
+ int finalSize = 0;
+ for (int i = 0 ; i < origSize; i++ ) {
+ String s = locales[i];
+ int len = s.length();
+ if (len == 5) {
+ String language = s.substring(0, 2);
+ String country = s.substring(3, 5);
+ Locale l = new Locale(language, country);
+
+ if (finalSize == 0) {
+ preprocess[finalSize++] =
+ new Loc(toTitleCase(l.getDisplayName(l)), l);
+ } else {
+ // check previous entry:
+ // same lang and a country -> upgrade to full name and
+ // insert ours with full name
+ // diff lang -> insert ours with lang-only name
+ if (preprocess[finalSize-1].locale.getLanguage().equals(
+ language)) {
+ preprocess[finalSize-1].label = toTitleCase(
+ preprocess[finalSize-1].locale.getDisplayName());
+ preprocess[finalSize++] =
+ new Loc(toTitleCase(l.getDisplayName()), l);
+ } else {
+ String displayName;
+ if (s.equals("zz_ZZ")) {
+ } else {
+ displayName = toTitleCase(l.getDisplayName(l));
+ preprocess[finalSize++] = new Loc(displayName, l);
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < finalSize ; i++) {
+ uniqueLocales.add(preprocess[i]);
+ }
+ return uniqueLocales;
+ }
+
+ private static String toTitleCase(String s) {
+ if (s.length() == 0) {
+ return s;
+ }
+
+ return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+ }
+
+}
diff --git a/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/src/com/android/inputmethod/latin/KeyboardSwitcher.java
index c82587b71..529edeb81 100644
--- a/src/com/android/inputmethod/latin/KeyboardSwitcher.java
+++ b/src/com/android/inputmethod/latin/KeyboardSwitcher.java
@@ -17,8 +17,14 @@
package com.android.inputmethod.latin;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.inputmethodservice.InputMethodService;
+
public class KeyboardSwitcher {
public static final int MODE_TEXT = 1;
@@ -27,6 +33,7 @@ public class KeyboardSwitcher {
public static final int MODE_URL = 4;
public static final int MODE_EMAIL = 5;
public static final int MODE_IM = 6;
+ public static final int MODE_WEB = 7;
public static final int MODE_TEXT_QWERTY = 0;
public static final int MODE_TEXT_ALPHA = 1;
@@ -36,34 +43,62 @@ public class KeyboardSwitcher {
public static final int KEYBOARDMODE_URL = R.id.mode_url;
public static final int KEYBOARDMODE_EMAIL = R.id.mode_email;
public static final int KEYBOARDMODE_IM = R.id.mode_im;
+ public static final int KEYBOARDMODE_WEB = R.id.mode_webentry;
private static final int SYMBOLS_MODE_STATE_NONE = 0;
private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
LatinKeyboardView mInputView;
- LatinIME mContext;
+ private static final int[] ALPHABET_MODES = {
+ KEYBOARDMODE_NORMAL,
+ KEYBOARDMODE_URL,
+ KEYBOARDMODE_EMAIL,
+ KEYBOARDMODE_IM,
+ KEYBOARDMODE_WEB};
+
+ //LatinIME mContext;
+ Context mContext;
+ InputMethodService mInputMethodService;
private KeyboardId mSymbolsId;
private KeyboardId mSymbolsShiftedId;
private KeyboardId mCurrentId;
private Map<KeyboardId, LatinKeyboard> mKeyboards;
-
- private int mMode;
+
+ private int mMode; /** One of the MODE_XXX values */
private int mImeOptions;
private int mTextMode = MODE_TEXT_QWERTY;
private boolean mIsSymbols;
+ private boolean mHasVoice;
+ private boolean mVoiceOnPrimary;
private boolean mPreferSymbols;
private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
private int mLastDisplayWidth;
+ private LanguageSwitcher mLanguageSwitcher;
+ private Locale mInputLocale;
+ private boolean mEnableMultipleLanguages;
- KeyboardSwitcher(LatinIME context) {
+ KeyboardSwitcher(Context context, InputMethodService ims) {
mContext = context;
mKeyboards = new HashMap<KeyboardId, LatinKeyboard>();
- mSymbolsId = new KeyboardId(R.xml.kbd_symbols);
- mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift);
+ mSymbolsId = new KeyboardId(R.xml.kbd_symbols, false);
+ mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift, false);
+ mInputMethodService = ims;
+ }
+
+ /**
+ * Sets the input locale, when there are multiple locales for input.
+ * If no locale switching is required, then the locale should be set to null.
+ * @param locale the current input locale, or null for default locale with no locale
+ * button.
+ */
+ void setLanguageSwitcher(LanguageSwitcher languageSwitcher) {
+ mLanguageSwitcher = languageSwitcher;
+ mInputLocale = mLanguageSwitcher.getInputLocale();
+ mEnableMultipleLanguages = mLanguageSwitcher.getLocaleCount() > 1;
}
void setInputView(LatinKeyboardView inputView) {
@@ -75,12 +110,13 @@ public class KeyboardSwitcher {
// Configuration change is coming after the keyboard gets recreated. So don't rely on that.
// If keyboards have already been made, check if we have a screen width change and
// create the keyboard layouts again at the correct orientation
- int displayWidth = mContext.getMaxWidth();
+ int displayWidth = mInputMethodService.getMaxWidth();
if (displayWidth == mLastDisplayWidth) return;
mLastDisplayWidth = displayWidth;
if (!forceCreate) mKeyboards.clear();
- mSymbolsId = new KeyboardId(R.xml.kbd_symbols);
- mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift);
+ mSymbolsId = new KeyboardId(R.xml.kbd_symbols, mHasVoice && !mVoiceOnPrimary);
+ mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift,
+ mHasVoice && !mVoiceOnPrimary);
}
/**
@@ -89,17 +125,19 @@ public class KeyboardSwitcher {
*/
private static class KeyboardId {
public int mXml;
- public int mMode;
+ public int mKeyboardMode; /** A KEYBOARDMODE_XXX value */
public boolean mEnableShiftLock;
+ public boolean mHasVoice;
- public KeyboardId(int xml, int mode, boolean enableShiftLock) {
+ public KeyboardId(int xml, int mode, boolean enableShiftLock, boolean hasVoice) {
this.mXml = xml;
- this.mMode = mode;
+ this.mKeyboardMode = mode;
this.mEnableShiftLock = enableShiftLock;
+ this.mHasVoice = hasVoice;
}
- public KeyboardId(int xml) {
- this(xml, 0, false);
+ public KeyboardId(int xml, boolean hasVoice) {
+ this(xml, 0, false, hasVoice);
}
public boolean equals(Object other) {
@@ -107,27 +145,49 @@ public class KeyboardSwitcher {
}
public boolean equals(KeyboardId other) {
- return other.mXml == this.mXml && other.mMode == this.mMode;
+ return other.mXml == this.mXml
+ && other.mKeyboardMode == this.mKeyboardMode
+ && other.mEnableShiftLock == this.mEnableShiftLock
+ && other.mHasVoice == this.mHasVoice;
}
public int hashCode() {
- return (mXml + 1) * (mMode + 1) * (mEnableShiftLock ? 2 : 1);
+ return (mXml + 1) * (mKeyboardMode + 1) * (mEnableShiftLock ? 2 : 1)
+ * (mHasVoice ? 4 : 8);
+ }
+ }
+
+ void setVoiceMode(boolean enableVoice, boolean voiceOnPrimary) {
+ if (enableVoice != mHasVoice || voiceOnPrimary != mVoiceOnPrimary) {
+ mKeyboards.clear();
}
+ mHasVoice = enableVoice;
+ mVoiceOnPrimary = voiceOnPrimary;
+ setKeyboardMode(mMode, mImeOptions, mHasVoice,
+ mIsSymbols);
}
- void setKeyboardMode(int mode, int imeOptions) {
+ boolean hasVoiceButton(boolean isSymbols) {
+ return mHasVoice && (isSymbols != mVoiceOnPrimary);
+ }
+
+ void setKeyboardMode(int mode, int imeOptions, boolean enableVoice) {
mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
mPreferSymbols = mode == MODE_SYMBOLS;
- setKeyboardMode(mode == MODE_SYMBOLS ? MODE_TEXT : mode, imeOptions,
+ setKeyboardMode(mode == MODE_SYMBOLS ? MODE_TEXT : mode, imeOptions, enableVoice,
mPreferSymbols);
}
- void setKeyboardMode(int mode, int imeOptions, boolean isSymbols) {
+ void setKeyboardMode(int mode, int imeOptions,
+ boolean enableVoice, boolean isSymbols) {
mMode = mode;
mImeOptions = imeOptions;
+ mHasVoice = enableVoice;
mIsSymbols = isSymbols;
+
mInputView.setPreviewEnabled(true);
KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
+
LatinKeyboard keyboard = getKeyboard(id);
if (mode == MODE_PHONE) {
@@ -140,45 +200,65 @@ public class KeyboardSwitcher {
keyboard.setShifted(false);
keyboard.setShiftLocked(keyboard.isShiftLocked());
keyboard.setImeOptions(mContext.getResources(), mMode, imeOptions);
-
}
private LatinKeyboard getKeyboard(KeyboardId id) {
if (!mKeyboards.containsKey(id)) {
+ Resources orig = mContext.getResources();
+ Configuration conf = orig.getConfiguration();
+ Locale saveLocale = conf.locale;
+ conf.locale = mInputLocale;
+ orig.updateConfiguration(conf, null);
LatinKeyboard keyboard = new LatinKeyboard(
- mContext, id.mXml, id.mMode);
+ mContext, id.mXml, id.mKeyboardMode, id.mHasVoice);
+ keyboard.setLanguageSwitcher(mLanguageSwitcher);
+ if (id.mKeyboardMode == KEYBOARDMODE_NORMAL
+ || id.mKeyboardMode == KEYBOARDMODE_URL
+ || id.mKeyboardMode == KEYBOARDMODE_IM
+ || id.mKeyboardMode == KEYBOARDMODE_EMAIL
+ || id.mKeyboardMode == KEYBOARDMODE_WEB
+ ) {
+ keyboard.setExtension(R.xml.kbd_extension);
+ }
+
if (id.mEnableShiftLock) {
keyboard.enableShiftLock();
}
mKeyboards.put(id, keyboard);
+
+ conf.locale = saveLocale;
+ orig.updateConfiguration(conf, null);
}
return mKeyboards.get(id);
}
private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
+ boolean hasVoice = hasVoiceButton(isSymbols);
if (isSymbols) {
return (mode == MODE_PHONE)
- ? new KeyboardId(R.xml.kbd_phone_symbols) : new KeyboardId(R.xml.kbd_symbols);
+ ? new KeyboardId(R.xml.kbd_phone_symbols, hasVoice)
+ : new KeyboardId(R.xml.kbd_symbols, hasVoice);
}
-
switch (mode) {
case MODE_TEXT:
if (mTextMode == MODE_TEXT_QWERTY) {
- return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_NORMAL, true);
+ return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_NORMAL, true, hasVoice);
} else if (mTextMode == MODE_TEXT_ALPHA) {
- return new KeyboardId(R.xml.kbd_alpha, KEYBOARDMODE_NORMAL, true);
+ return new KeyboardId(R.xml.kbd_alpha, KEYBOARDMODE_NORMAL, true, hasVoice);
}
break;
case MODE_SYMBOLS:
- return new KeyboardId(R.xml.kbd_symbols);
+ return new KeyboardId(R.xml.kbd_symbols, hasVoice);
case MODE_PHONE:
- return new KeyboardId(R.xml.kbd_phone);
+ return new KeyboardId(R.xml.kbd_phone, hasVoice);
case MODE_URL:
- return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_URL, true);
+ return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_URL, true, hasVoice);
case MODE_EMAIL:
- return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_EMAIL, true);
+ return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_EMAIL, true, hasVoice);
case MODE_IM:
- return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_IM, true);
+ return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_IM, true, hasVoice);
+ case MODE_WEB:
+ return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_WEB, true, hasVoice);
}
return null;
}
@@ -200,7 +280,7 @@ public class KeyboardSwitcher {
mTextMode = position;
}
if (isTextMode()) {
- setKeyboardMode(MODE_TEXT, mImeOptions);
+ setKeyboardMode(MODE_TEXT, mImeOptions, mHasVoice);
}
}
@@ -209,11 +289,13 @@ public class KeyboardSwitcher {
}
boolean isAlphabetMode() {
- KeyboardId current = mCurrentId;
- return current.mMode == KEYBOARDMODE_NORMAL
- || current.mMode == KEYBOARDMODE_URL
- || current.mMode == KEYBOARDMODE_EMAIL
- || current.mMode == KEYBOARDMODE_IM;
+ int currentMode = mCurrentId.mKeyboardMode;
+ for (Integer mode : ALPHABET_MODES) {
+ if (currentMode == mode) {
+ return true;
+ }
+ }
+ return false;
}
void toggleShift() {
@@ -237,7 +319,7 @@ public class KeyboardSwitcher {
}
void toggleSymbols() {
- setKeyboardMode(mMode, mImeOptions, !mIsSymbols);
+ setKeyboardMode(mMode, mImeOptions, mHasVoice, !mIsSymbols);
if (mIsSymbols && !mPreferSymbols) {
mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
} else {
diff --git a/src/com/android/inputmethod/latin/LanguageSwitcher.java b/src/com/android/inputmethod/latin/LanguageSwitcher.java
new file mode 100644
index 000000000..3fa882e44
--- /dev/null
+++ b/src/com/android/inputmethod/latin/LanguageSwitcher.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import java.util.Locale;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.preference.PreferenceManager;
+
+/**
+ * Keeps track of list of selected input languages and the current
+ * input language that the user has selected.
+ */
+public class LanguageSwitcher {
+
+ private Locale[] mLocales;
+ private LatinIME mIme;
+ private String[] mSelectedLanguageArray;
+ private String mSelectedLanguages;
+ private int mCurrentIndex = 0;
+ private String mDefaultInputLanguage;
+ private Locale mDefaultInputLocale;
+
+ public LanguageSwitcher(LatinIME ime) {
+ mIme = ime;
+ mLocales = new Locale[0];
+ }
+
+ public Locale[] getLocales() {
+ return mLocales;
+ }
+
+ public int getLocaleCount() {
+ return mLocales.length;
+ }
+
+ /**
+ * Loads the currently selected input languages from shared preferences.
+ * @param sp
+ * @return whether there was any change
+ */
+ public boolean loadLocales(SharedPreferences sp) {
+ String selectedLanguages = sp.getString(LatinIME.PREF_SELECTED_LANGUAGES, null);
+ String currentLanguage = sp.getString(LatinIME.PREF_INPUT_LANGUAGE, null);
+ if (selectedLanguages == null || selectedLanguages.length() < 1) {
+ loadDefaults();
+ if (mLocales.length == 0) {
+ return false;
+ }
+ mLocales = new Locale[0];
+ return true;
+ }
+ if (selectedLanguages.equals(mSelectedLanguages)) {
+ return false;
+ }
+ mSelectedLanguageArray = selectedLanguages.split(",");
+ mSelectedLanguages = selectedLanguages; // Cache it for comparison later
+ constructLocales();
+ mCurrentIndex = 0;
+ if (currentLanguage != null) {
+ // Find the index
+ mCurrentIndex = 0;
+ for (int i = 0; i < mLocales.length; i++) {
+ if (mSelectedLanguageArray[i].equals(currentLanguage)) {
+ mCurrentIndex = i;
+ break;
+ }
+ }
+ // If we didn't find the index, use the first one
+ }
+ return true;
+ }
+
+ private void loadDefaults() {
+ mDefaultInputLocale = mIme.getResources().getConfiguration().locale;
+ mDefaultInputLanguage = mDefaultInputLocale.getLanguage() + "_"
+ + mDefaultInputLocale.getCountry();
+ }
+
+ private void constructLocales() {
+ mLocales = new Locale[mSelectedLanguageArray.length];
+ for (int i = 0; i < mLocales.length; i++) {
+ mLocales[i] = new Locale(mSelectedLanguageArray[i]);
+ }
+ }
+
+ /**
+ * Returns the currently selected input language code, or the display language code if
+ * no specific locale was selected for input.
+ */
+ public String getInputLanguage() {
+ if (getLocaleCount() == 0) return mDefaultInputLanguage;
+
+ return mSelectedLanguageArray[mCurrentIndex];
+ }
+
+ /**
+ * Returns the list of enabled language codes.
+ */
+ public String[] getEnabledLanguages() {
+ return mSelectedLanguageArray;
+ }
+
+ /**
+ * Returns the currently selected input locale, or the display locale if no specific
+ * locale was selected for input.
+ * @return
+ */
+ public Locale getInputLocale() {
+ if (getLocaleCount() == 0) return mDefaultInputLocale;
+
+ return mLocales[mCurrentIndex];
+ }
+
+ /**
+ * Returns the next input locale in the list. Wraps around to the beginning of the
+ * list if we're at the end of the list.
+ * @return
+ */
+ public Locale getNextInputLocale() {
+ if (getLocaleCount() == 0) return mDefaultInputLocale;
+
+ return mLocales[(mCurrentIndex + 1) % mLocales.length];
+ }
+
+ /**
+ * Returns the previous input locale in the list. Wraps around to the end of the
+ * list if we're at the beginning of the list.
+ * @return
+ */
+ public Locale getPrevInputLocale() {
+ if (getLocaleCount() == 0) return mDefaultInputLocale;
+
+ return mLocales[(mCurrentIndex - 1 + mLocales.length) % mLocales.length];
+ }
+
+ public void reset() {
+ mCurrentIndex = 0;
+ }
+
+ public void next() {
+ mCurrentIndex++;
+ if (mCurrentIndex >= mLocales.length) mCurrentIndex = 0; // Wrap around
+ }
+
+ public void prev() {
+ mCurrentIndex--;
+ if (mCurrentIndex < 0) mCurrentIndex = mLocales.length - 1; // Wrap around
+ }
+
+ public void persist() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mIme);
+ Editor editor = sp.edit();
+ editor.putString(LatinIME.PREF_INPUT_LANGUAGE, getInputLanguage());
+ editor.commit();
+ }
+}
diff --git a/src/com/android/inputmethod/latin/LatinIME.java b/src/com/android/inputmethod/latin/LatinIME.java
index 8b76dbd39..8b9c0cac7 100644
--- a/src/com/android/inputmethod/latin/LatinIME.java
+++ b/src/com/android/inputmethod/latin/LatinIME.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2008-2009 Google Inc.
- *
+ *
* 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
@@ -16,14 +16,20 @@
package com.android.inputmethod.latin;
+import com.google.android.collect.Lists;
+
import android.app.AlertDialog;
+import android.backup.BackupManager;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
@@ -41,38 +47,98 @@ import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
+import com.android.inputmethod.voice.EditingUtil;
+import com.android.inputmethod.voice.FieldContext;
+import com.android.inputmethod.voice.SettingsUtil;
+import com.android.inputmethod.voice.VoiceInput;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
/**
* Input method implementation for Qwerty'ish keyboard.
*/
-public class LatinIME extends InputMethodService
- implements KeyboardView.OnKeyboardActionListener {
+public class LatinIME extends InputMethodService
+ implements KeyboardView.OnKeyboardActionListener,
+ VoiceInput.UiListener,
+ SharedPreferences.OnSharedPreferenceChangeListener {
+ private static final String TAG = "LatinIME";
static final boolean DEBUG = false;
static final boolean TRACE = false;
-
+ static final boolean VOICE_INSTALLED = true;
+ static final boolean ENABLE_VOICE_BUTTON = true;
+
private static final String PREF_VIBRATE_ON = "vibrate_on";
private static final String PREF_SOUND_ON = "sound_on";
private static final String PREF_AUTO_CAP = "auto_cap";
private static final String PREF_QUICK_FIXES = "quick_fixes";
private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions";
private static final String PREF_AUTO_COMPLETE = "auto_complete";
+ private static final String PREF_ENABLE_VOICE = "enable_voice_input";
+ private static final String PREF_VOICE_SERVER_URL = "voice_server_url";
+ private static final String PREF_VOICE_MAIN = "voice_on_main";
+
+ // Whether or not the user has used voice input before (and thus, whether to show the
+ // first-run warning dialog or not).
+ private static final String PREF_HAS_USED_VOICE_INPUT = "has_used_voice_input";
+
+ // Whether or not the user has used voice input from an unsupported locale UI before.
+ // For example, the user has a Chinese UI but activates voice input.
+ private static final String PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE =
+ "has_used_voice_input_unsupported_locale";
+
+ // A list of locales which are supported by default for voice input, unless we get a
+ // different list from Gservices.
+ public static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
+ "en " +
+ "en_US " +
+ "en_GB " +
+ "en_AU " +
+ "en_CA " +
+ "en_IE " +
+ "en_IN " +
+ "en_NZ " +
+ "en_SG " +
+ "en_ZA ";
+
+ // The private IME option used to indicate that no microphone should be shown for a
+ // given text field. For instance this is specified by the search dialog when the
+ // dialog is already showing a voice search button.
+ private static final String IME_OPTION_NO_MICROPHONE = "nm";
+
+ public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
+ public static final String PREF_INPUT_LANGUAGE = "input_language";
private static final int MSG_UPDATE_SUGGESTIONS = 0;
private static final int MSG_START_TUTORIAL = 1;
private static final int MSG_UPDATE_SHIFT_STATE = 2;
-
+ private static final int MSG_VOICE_RESULTS = 3;
+ private static final int MSG_START_LISTENING_AFTER_SWIPE = 4;
+
+ // If we detect a swipe gesture within N ms of typing, then swipe is
+ // ignored, since it may in fact be two key presses in quick succession.
+ private static final long MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE = 1000;
+
+ // If we detect a swipe gesture, and the user types N ms later, cancel the
+ // swipe since it was probably a false trigger.
+ private static final long MIN_MILLIS_AFTER_SWIPE_TO_WAIT_FOR_TYPING = 500;
+
// How many continuous deletes at which to start deleting at a higher speed.
private static final int DELETE_ACCELERATE_AT = 20;
// Key events coming any faster than this are long-presses.
@@ -84,54 +150,79 @@ public class LatinIME extends InputMethodService
// A word that is frequently typed and get's promoted to the user dictionary, uses this
// frequency.
static final int FREQUENCY_FOR_AUTO_ADD = 250;
-
+
static final int KEYCODE_ENTER = '\n';
static final int KEYCODE_SPACE = ' ';
// Contextual menu positions
private static final int POS_SETTINGS = 0;
private static final int POS_METHOD = 1;
-
+
private LatinKeyboardView mInputView;
private CandidateViewContainer mCandidateViewContainer;
private CandidateView mCandidateView;
private Suggest mSuggest;
private CompletionInfo[] mCompletions;
-
+
private AlertDialog mOptionsDialog;
-
+ private AlertDialog mVoiceWarningDialog;
+
KeyboardSwitcher mKeyboardSwitcher;
-
+
private UserDictionary mUserDictionary;
private ContactsDictionary mContactsDictionary;
private ExpandableDictionary mAutoDictionary;
-
+
+ private Hints mHints;
+
+ Resources mResources;
+
private String mLocale;
+ private LanguageSwitcher mLanguageSwitcher;
private StringBuilder mComposing = new StringBuilder();
private WordComposer mWord = new WordComposer();
private int mCommittedLength;
private boolean mPredicting;
+ private boolean mRecognizing;
+ private boolean mAfterVoiceInput;
+ private boolean mImmediatelyAfterVoiceInput;
+ private boolean mShowingVoiceSuggestions;
+ private boolean mImmediatelyAfterVoiceSuggestions;
+ private boolean mVoiceInputHighlighted;
+ private boolean mEnableVoiceButton;
private CharSequence mBestWord;
private boolean mPredictionOn;
private boolean mCompletionOn;
+ private boolean mHasDictionary;
private boolean mAutoSpace;
+ private boolean mAutoCorrectEnabled;
private boolean mAutoCorrectOn;
private boolean mCapsLock;
+ private boolean mPasswordText;
+ private boolean mEmailText;
private boolean mVibrateOn;
private boolean mSoundOn;
private boolean mAutoCap;
private boolean mQuickFixes;
+ private boolean mHasUsedVoiceInput;
+ private boolean mHasUsedVoiceInputUnsupportedLocale;
+ private boolean mLocaleSupportedForVoiceInput;
private boolean mShowSuggestions;
+ private boolean mSuggestionShouldReplaceCurrentWord;
+ private boolean mIsShowingHint;
private int mCorrectionMode;
+ private boolean mEnableVoice = true;
+ private boolean mVoiceOnPrimary;
private int mOrientation;
+ private List<CharSequence> mSuggestPuncList;
// Indicates whether the suggestion strip is to be on in landscape
private boolean mJustAccepted;
private CharSequence mJustRevertedSeparator;
private int mDeleteCount;
private long mLastKeyTime;
-
+
private Tutorial mTutorial;
private Vibrator mVibrator;
@@ -144,7 +235,19 @@ public class LatinIME extends InputMethodService
private String mWordSeparators;
private String mSentenceSeparators;
-
+ private VoiceInput mVoiceInput;
+ private VoiceResults mVoiceResults = new VoiceResults();
+ private long mSwipeTriggerTimeMillis;
+
+ // For each word, a list of potential replacements, usually from voice.
+ private Map<String, List<CharSequence>> mWordToSuggestions = new HashMap();
+
+ private class VoiceResults {
+ List<String> candidates;
+ Map<String, List<CharSequence>> alternatives;
+ }
+ private boolean mRefreshKeyboardRequired;
+
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -166,6 +269,13 @@ public class LatinIME extends InputMethodService
case MSG_UPDATE_SHIFT_STATE:
updateShiftKeyState(getCurrentInputEditorInfo());
break;
+ case MSG_VOICE_RESULTS:
+ handleVoiceResults();
+ break;
+ case MSG_START_LISTENING_AFTER_SWIPE:
+ if (mLastKeyTime < mSwipeTriggerTimeMillis) {
+ startListening(true);
+ }
}
}
};
@@ -173,36 +283,83 @@ public class LatinIME extends InputMethodService
@Override public void onCreate() {
super.onCreate();
//setStatusIcon(R.drawable.ime_qwerty);
- mKeyboardSwitcher = new KeyboardSwitcher(this);
- final Configuration conf = getResources().getConfiguration();
- initSuggest(conf.locale.toString());
+ mResources = getResources();
+ final Configuration conf = mResources.getConfiguration();
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mLanguageSwitcher = new LanguageSwitcher(this);
+ mLanguageSwitcher.loadLocales(prefs);
+ mKeyboardSwitcher = new KeyboardSwitcher(this, this);
+ mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
+ boolean enableMultipleLanguages = mLanguageSwitcher.getLocaleCount() > 0;
+ String inputLanguage = mLanguageSwitcher.getInputLanguage();
+ if (inputLanguage == null) {
+ inputLanguage = conf.locale.toString();
+ }
+ initSuggest(inputLanguage);
mOrientation = conf.orientation;
+ initSuggestPuncList();
- mVibrateDuration = getResources().getInteger(R.integer.vibrate_duration_ms);
+ mVibrateDuration = mResources.getInteger(R.integer.vibrate_duration_ms);
// register to receive ringer mode changes for silent mode
IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(mReceiver, filter);
+ if (VOICE_INSTALLED) {
+ mVoiceInput = new VoiceInput(this, this);
+ mHints = new Hints(this, new Hints.Display() {
+ public void showHint(int viewResource) {
+ LayoutInflater inflater = (LayoutInflater) getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View view = inflater.inflate(viewResource, null);
+ setCandidatesView(view);
+ setCandidatesViewShown(true);
+ mIsShowingHint = true;
+ }
+ });
+ }
+ prefs.registerOnSharedPreferenceChangeListener(this);
}
-
+
private void initSuggest(String locale) {
mLocale = locale;
+
+ Resources orig = getResources();
+ Configuration conf = orig.getConfiguration();
+ Locale saveLocale = conf.locale;
+ conf.locale = new Locale(locale);
+ orig.updateConfiguration(conf, orig.getDisplayMetrics());
+ if (mSuggest != null) {
+ mSuggest.close();
+ }
mSuggest = new Suggest(this, R.raw.main);
- mSuggest.setCorrectionMode(mCorrectionMode);
+ if (mUserDictionary != null) mUserDictionary.close();
mUserDictionary = new UserDictionary(this);
- mContactsDictionary = new ContactsDictionary(this);
- mAutoDictionary = new AutoDictionary(this);
+ if (mContactsDictionary == null) {
+ mContactsDictionary = new ContactsDictionary(this);
+ }
+ // TODO: Save and restore the dictionary for the current input language.
+ if (mAutoDictionary == null) {
+ mAutoDictionary = new AutoDictionary(this);
+ }
mSuggest.setUserDictionary(mUserDictionary);
mSuggest.setContactsDictionary(mContactsDictionary);
mSuggest.setAutoDictionary(mAutoDictionary);
- mWordSeparators = getResources().getString(R.string.word_separators);
- mSentenceSeparators = getResources().getString(R.string.sentence_separators);
+ updateCorrectionMode();
+ mWordSeparators = mResources.getString(R.string.word_separators);
+ mSentenceSeparators = mResources.getString(R.string.sentence_separators);
+
+ conf.locale = saveLocale;
+ orig.updateConfiguration(conf, orig.getDisplayMetrics());
}
-
- @Override public void onDestroy() {
+
+ @Override
+ public void onDestroy() {
mUserDictionary.close();
mContactsDictionary.close();
unregisterReceiver(mReceiver);
+ if (VOICE_INSTALLED) {
+ mVoiceInput.destroy();
+ }
super.onDestroy();
}
@@ -213,13 +370,12 @@ public class LatinIME extends InputMethodService
}
// If orientation changed while predicting, commit the change
if (conf.orientation != mOrientation) {
- commitTyped(getCurrentInputConnection());
+ InputConnection ic = getCurrentInputConnection();
+ commitTyped(ic);
+ if (ic != null) ic.finishComposingText(); // For voice input
mOrientation = conf.orientation;
}
- if (mKeyboardSwitcher == null) {
- mKeyboardSwitcher = new KeyboardSwitcher(this);
- }
- mKeyboardSwitcher.makeKeyboards(true);
+ reloadKeyboards();
super.onConfigurationChanged(conf);
}
@@ -230,11 +386,28 @@ public class LatinIME extends InputMethodService
mKeyboardSwitcher.setInputView(mInputView);
mKeyboardSwitcher.makeKeyboards(true);
mInputView.setOnKeyboardActionListener(this);
- mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT, 0);
+ mKeyboardSwitcher.setKeyboardMode(
+ KeyboardSwitcher.MODE_TEXT, 0,
+ shouldShowVoiceButton(makeFieldContext(), getCurrentInputEditorInfo()));
return mInputView;
}
@Override
+ public void onInitializeInterface() {
+ // Create a new view associated with voice input if the old
+ // view is stuck in another layout (e.g. if switching from
+ // portrait to landscape while speaking)
+ // NOTE: This must be done here because for some reason
+ // onCreateInputView isn't called after an orientation change while
+ // speech rec is in progress.
+ if (mVoiceInput != null && mVoiceInput.getView().getParent() != null) {
+ mVoiceInput.newView();
+ }
+
+ super.onInitializeInterface();
+ }
+
+ @Override
public View onCreateCandidatesView() {
mKeyboardSwitcher.makeKeyboards(true);
mCandidateViewContainer = (CandidateViewContainer) getLayoutInflater().inflate(
@@ -246,43 +419,71 @@ public class LatinIME extends InputMethodService
return mCandidateViewContainer;
}
- @Override
+ @Override
public void onStartInputView(EditorInfo attribute, boolean restarting) {
// In landscape mode, this method gets called without the input view being created.
if (mInputView == null) {
return;
}
+ if (mRefreshKeyboardRequired) {
+ mRefreshKeyboardRequired = false;
+ toggleLanguage(true, true);
+ }
+
mKeyboardSwitcher.makeKeyboards(false);
TextEntryState.newSession(this);
+ // Most such things we decide below in the switch statement, but we need to know
+ // now whether this is a password text field, because we need to know now (before
+ // the switch statement) whether we want to enable the voice button.
+ mPasswordText = false;
+ int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
+ if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
+ variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
+ mPasswordText = true;
+ }
+
+ mEnableVoiceButton = shouldShowVoiceButton(makeFieldContext(), attribute);
+ final boolean enableVoiceButton = mEnableVoiceButton && mEnableVoice;
+
+ mAfterVoiceInput = false;
+ mImmediatelyAfterVoiceInput = false;
+ mShowingVoiceSuggestions = false;
+ mImmediatelyAfterVoiceSuggestions = false;
+ mVoiceInputHighlighted = false;
boolean disableAutoCorrect = false;
+ mWordToSuggestions.clear();
+ mInputTypeNoAutoCorrect = false;
mPredictionOn = false;
mCompletionOn = false;
mCompletions = null;
mCapsLock = false;
- switch (attribute.inputType&EditorInfo.TYPE_MASK_CLASS) {
+ mEmailText = false;
+ switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) {
case EditorInfo.TYPE_CLASS_NUMBER:
case EditorInfo.TYPE_CLASS_DATETIME:
mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_SYMBOLS,
- attribute.imeOptions);
+ attribute.imeOptions, enableVoiceButton);
break;
case EditorInfo.TYPE_CLASS_PHONE:
mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_PHONE,
- attribute.imeOptions);
+ attribute.imeOptions, enableVoiceButton);
break;
case EditorInfo.TYPE_CLASS_TEXT:
mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
- attribute.imeOptions);
+ attribute.imeOptions, enableVoiceButton);
//startPrediction();
mPredictionOn = true;
// Make sure that passwords are not displayed in candidate view
- int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ) {
mPredictionOn = false;
}
+ if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
+ mEmailText = true;
+ }
if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|| variation == EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME) {
mAutoSpace = false;
@@ -292,33 +493,35 @@ public class LatinIME extends InputMethodService
if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
mPredictionOn = false;
mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_EMAIL,
- attribute.imeOptions);
+ attribute.imeOptions, enableVoiceButton);
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
mPredictionOn = false;
mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_URL,
- attribute.imeOptions);
+ attribute.imeOptions, enableVoiceButton);
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_IM,
- attribute.imeOptions);
+ attribute.imeOptions, enableVoiceButton);
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
mPredictionOn = false;
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
+ mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_WEB,
+ attribute.imeOptions, enableVoiceButton);
// If it's a browser edit field and auto correct is not ON explicitly, then
// disable auto correction, but keep suggestions on.
if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
- disableAutoCorrect = true;
+ mInputTypeNoAutoCorrect = true;
}
}
// If NO_SUGGESTIONS is set, don't do prediction.
if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
mPredictionOn = false;
- disableAutoCorrect = true;
+ mInputTypeNoAutoCorrect = true;
}
// If it's not multiline and the autoCorrect flag is not set, then don't correct
if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
(attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
- disableAutoCorrect = true;
+ mInputTypeNoAutoCorrect = true;
}
if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
mPredictionOn = false;
@@ -328,16 +531,18 @@ public class LatinIME extends InputMethodService
break;
default:
mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
- attribute.imeOptions);
+ attribute.imeOptions, enableVoiceButton);
updateShiftKeyState(attribute);
}
mInputView.closing();
mComposing.setLength(0);
mPredicting = false;
mDeleteCount = 0;
- setCandidatesViewShown(false);
- if (mCandidateView != null) mCandidateView.setSuggestions(null, false, false, false);
loadSettings();
+
+ setCandidatesViewShown(false);
+ setSuggestions(null, false, false, false);
+
// Override auto correct
if (disableAutoCorrect) {
mAutoCorrectOn = false;
@@ -345,10 +550,12 @@ public class LatinIME extends InputMethodService
mCorrectionMode = Suggest.CORRECTION_BASIC;
}
}
+ // If the dictionary is not big enough, don't auto correct
+ mHasDictionary = mSuggest.hasMainDictionary();
+
+ updateCorrectionMode();
+
mInputView.setProximityCorrectionEnabled(true);
- if (mSuggest != null) {
- mSuggest.setCorrectionMode(mCorrectionMode);
- }
mPredictionOn = mPredictionOn && mCorrectionMode > 0;
checkTutorial(attribute.privateImeOptions);
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
@@ -358,9 +565,34 @@ public class LatinIME extends InputMethodService
public void onFinishInput() {
super.onFinishInput();
+ if (VOICE_INSTALLED && mAfterVoiceInput) {
+ mVoiceInput.logInputEnded();
+ }
+
+ if (VOICE_INSTALLED) {
+ mVoiceInput.flushLogs();
+ }
+
if (mInputView != null) {
mInputView.closing();
}
+ if (VOICE_INSTALLED && mRecognizing) {
+ mVoiceInput.cancel();
+ }
+ }
+
+ @Override
+ public void onUpdateExtractedText(int token, ExtractedText text) {
+ super.onUpdateExtractedText(token, text);
+ InputConnection ic = getCurrentInputConnection();
+ if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
+ mVoiceInput.logTextModified();
+
+ if (mHints.showPunctuationHintIfNecessary(ic)) {
+ mVoiceInput.logPunctuationHintDisplayed();
+ }
+ }
+ mImmediatelyAfterVoiceInput = false;
}
@Override
@@ -369,10 +601,22 @@ public class LatinIME extends InputMethodService
int candidatesStart, int candidatesEnd) {
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
candidatesStart, candidatesEnd);
+
+ if (DEBUG) {
+ Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
+ + ", ose=" + oldSelEnd
+ + ", nss=" + newSelStart
+ + ", nse=" + newSelEnd
+ + ", cs=" + candidatesStart
+ + ", ce=" + candidatesEnd);
+ }
+
+ mSuggestionShouldReplaceCurrentWord = false;
// If the current selection in the text view changes, we should
// clear whatever candidate text we have.
- if (mComposing.length() > 0 && mPredicting && (newSelStart != candidatesEnd
- || newSelEnd != candidatesEnd)) {
+ if ((((mComposing.length() > 0 && mPredicting) || mVoiceInputHighlighted)
+ && (newSelStart != candidatesEnd
+ || newSelEnd != candidatesEnd))) {
mComposing.setLength(0);
mPredicting = false;
updateSuggestions();
@@ -381,25 +625,58 @@ public class LatinIME extends InputMethodService
if (ic != null) {
ic.finishComposingText();
}
+ mVoiceInputHighlighted = false;
} else if (!mPredicting && !mJustAccepted
&& TextEntryState.getState() == TextEntryState.STATE_ACCEPTED_DEFAULT) {
TextEntryState.reset();
}
mJustAccepted = false;
postUpdateShiftKeyState();
+
+ if (VOICE_INSTALLED) {
+ if (mShowingVoiceSuggestions) {
+ if (mImmediatelyAfterVoiceSuggestions) {
+ mImmediatelyAfterVoiceSuggestions = false;
+ } else {
+ updateSuggestions();
+ mShowingVoiceSuggestions = false;
+ }
+ }
+ if (VoiceInput.ENABLE_WORD_CORRECTIONS) {
+ // If we have alternatives for the current word, then show them.
+ String word = EditingUtil.getWordAtCursor(
+ getCurrentInputConnection(), getWordSeparators());
+ if (word != null && mWordToSuggestions.containsKey(word.trim())) {
+ mSuggestionShouldReplaceCurrentWord = true;
+ final List<CharSequence> suggestions = mWordToSuggestions.get(word.trim());
+
+ setSuggestions(suggestions, false, true, true);
+ setCandidatesViewShown(true);
+ }
+ }
+ }
}
@Override
public void hideWindow() {
+ if (mAfterVoiceInput) mVoiceInput.logInputEnded();
if (TRACE) Debug.stopMethodTracing();
if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
mOptionsDialog.dismiss();
mOptionsDialog = null;
}
+ if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
+ mVoiceInput.logKeyboardWarningDialogDismissed();
+ mVoiceWarningDialog.dismiss();
+ mVoiceWarningDialog = null;
+ }
if (mTutorial != null) {
mTutorial.close();
mTutorial = null;
}
+ if (VOICE_INSTALLED & mRecognizing) {
+ mVoiceInput.cancel();
+ }
super.hideWindow();
TextEntryState.endSession();
}
@@ -415,17 +692,17 @@ public class LatinIME extends InputMethodService
if (mCompletionOn) {
mCompletions = completions;
if (completions == null) {
- mCandidateView.setSuggestions(null, false, false, false);
+ setSuggestions(null, false, false, false);
return;
}
-
+
List<CharSequence> stringList = new ArrayList<CharSequence>();
for (int i=0; i<(completions != null ? completions.length : 0); i++) {
CompletionInfo ci = completions[i];
if (ci != null) stringList.add(ci.getText());
}
//CharSequence typedWord = mWord.getTypedWord();
- mCandidateView.setSuggestions(stringList, true, true, true);
+ setSuggestions(stringList, true, true, true);
mBestWord = null;
setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
}
@@ -438,7 +715,7 @@ public class LatinIME extends InputMethodService
super.setCandidatesViewShown(shown);
}
}
-
+
@Override
public void onComputeInsets(InputMethodService.Insets outInsets) {
super.onComputeInsets(outInsets);
@@ -446,7 +723,7 @@ public class LatinIME extends InputMethodService
outInsets.contentTopInsets = outInsets.visibleTopInsets;
}
}
-
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
@@ -486,7 +763,7 @@ public class LatinIME extends InputMethodService
}
// Enable shift key and DPAD to do selections
if (mInputView != null && mInputView.isShown() && mInputView.isShifted()) {
- event = new KeyEvent(event.getDownTime(), event.getEventTime(),
+ event = new KeyEvent(event.getDownTime(), event.getEventTime(),
event.getAction(), event.getKeyCode(), event.getRepeatCount(),
event.getDeviceId(), event.getScanCode(),
KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
@@ -499,6 +776,31 @@ public class LatinIME extends InputMethodService
return super.onKeyUp(keyCode, event);
}
+ private void revertVoiceInput() {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) ic.commitText("", 1);
+ updateSuggestions();
+ mVoiceInputHighlighted = false;
+ }
+
+ private void commitVoiceInput() {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) ic.finishComposingText();
+ updateSuggestions();
+ mVoiceInputHighlighted = false;
+ }
+
+ private void reloadKeyboards() {
+ if (mKeyboardSwitcher == null) {
+ mKeyboardSwitcher = new KeyboardSwitcher(this, this);
+ }
+ mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
+ if (mInputView != null) {
+ mKeyboardSwitcher.setVoiceMode(mEnableVoice, mVoiceOnPrimary);
+ }
+ mKeyboardSwitcher.makeKeyboards(true);
+ }
+
private void commitTyped(InputConnection inputConnection) {
if (mPredicting) {
mPredicting = false;
@@ -523,15 +825,19 @@ public class LatinIME extends InputMethodService
InputConnection ic = getCurrentInputConnection();
if (attr != null && mInputView != null && mKeyboardSwitcher.isAlphabetMode()
&& ic != null) {
- int caps = 0;
- EditorInfo ei = getCurrentInputEditorInfo();
- if (mAutoCap && ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
- caps = ic.getCursorCapsMode(attr.inputType);
- }
- mInputView.setShifted(mCapsLock || caps != 0);
+ mInputView.setShifted(mCapsLock || getCursorCapsMode(ic, attr) != 0);
}
}
-
+
+ private int getCursorCapsMode(InputConnection ic, EditorInfo attr) {
+ int caps = 0;
+ EditorInfo ei = getCurrentInputEditorInfo();
+ if (mAutoCap && ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
+ caps = ic.getCursorCapsMode(attr.inputType);
+ }
+ return caps;
+ }
+
private void swapPunctuationAndSpace() {
final InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
@@ -545,7 +851,7 @@ public class LatinIME extends InputMethodService
updateShiftKeyState(getCurrentInputEditorInfo());
}
}
-
+
private void doubleSpace() {
//if (!mAutoPunctuate) return;
if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
@@ -562,7 +868,20 @@ public class LatinIME extends InputMethodService
updateShiftKeyState(getCurrentInputEditorInfo());
}
}
-
+
+ private void maybeRemovePreviousPeriod(CharSequence text) {
+ final InputConnection ic = getCurrentInputConnection();
+ if (ic == null) return;
+
+ // When the text's first character is '.', remove the previous period
+ // if there is one.
+ CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
+ if (lastOne != null && lastOne.length() == 1 && lastOne.charAt(0) == '.'
+ && text.charAt(0) == '.') {
+ ic.deleteSurroundingText(1, 0);
+ }
+ }
+
public boolean addWordToDictionary(String word) {
mUserDictionary.addWord(word, 128);
return true;
@@ -575,12 +894,12 @@ public class LatinIME extends InputMethodService
return false;
}
}
-
+
// Implementation of KeyboardViewListener
public void onKey(int primaryCode, int[] keyCodes) {
long when = SystemClock.uptimeMillis();
- if (primaryCode != Keyboard.KEYCODE_DELETE ||
+ if (primaryCode != Keyboard.KEYCODE_DELETE ||
when > mLastKeyTime + QUICK_PRESS) {
mDeleteCount = 0;
}
@@ -601,6 +920,12 @@ public class LatinIME extends InputMethodService
case LatinKeyboardView.KEYCODE_OPTIONS:
showOptionsMenu();
break;
+ case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE:
+ toggleLanguage(false, true);
+ break;
+ case LatinKeyboardView.KEYCODE_PREV_LANGUAGE:
+ toggleLanguage(false, false);
+ break;
case LatinKeyboardView.KEYCODE_SHIFT_LONGPRESS:
if (mCapsLock) {
handleShift();
@@ -611,6 +936,14 @@ public class LatinIME extends InputMethodService
case Keyboard.KEYCODE_MODE_CHANGE:
changeKeyboardMode();
break;
+ case LatinKeyboardView.KEYCODE_VOICE:
+ if (VOICE_INSTALLED) {
+ startListening(false /* was a button press, was not a swipe */);
+ }
+ break;
+ case 9 /*Tab*/:
+ sendKeyChar((char) primaryCode);
+ break;
default:
if (isWordSeparator(primaryCode)) {
handleSeparator(primaryCode);
@@ -624,7 +957,7 @@ public class LatinIME extends InputMethodService
changeKeyboardMode();
}
}
-
+
public void onText(CharSequence text) {
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
@@ -632,6 +965,7 @@ public class LatinIME extends InputMethodService
if (mPredicting) {
commitTyped(ic);
}
+ maybeRemovePreviousPeriod(text);
ic.commitText(text, 1);
ic.endBatchEdit();
updateShiftKeyState(getCurrentInputEditorInfo());
@@ -639,6 +973,10 @@ public class LatinIME extends InputMethodService
}
private void handleBackspace() {
+ if (VOICE_INSTALLED && mVoiceInputHighlighted) {
+ revertVoiceInput();
+ return;
+ }
boolean deleteChar = false;
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
@@ -673,7 +1011,7 @@ public class LatinIME extends InputMethodService
}
private void handleShift() {
- Keyboard currentKeyboard = mInputView.getKeyboard();
+ mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE);
if (mKeyboardSwitcher.isAlphabetMode()) {
// Alphabet keyboard
checkToggleCapsLock();
@@ -682,8 +1020,11 @@ public class LatinIME extends InputMethodService
mKeyboardSwitcher.toggleShift();
}
}
-
+
private void handleCharacter(int primaryCode, int[] keyCodes) {
+ if (VOICE_INSTALLED && mVoiceInputHighlighted) {
+ commitVoiceInput();
+ }
if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) {
if (!mPredicting) {
mPredicting = true;
@@ -707,6 +1048,11 @@ public class LatinIME extends InputMethodService
mWord.add(primaryCode, keyCodes);
InputConnection ic = getCurrentInputConnection();
if (ic != null) {
+ // If it's the first letter, make note of auto-caps state
+ if (mWord.size() == 1) {
+ mWord.setAutoCapitalized(
+ getCursorCapsMode(ic, getCurrentInputEditorInfo()) != 0);
+ }
ic.setComposingText(mComposing, 1);
}
postUpdateSuggestions();
@@ -719,6 +1065,9 @@ public class LatinIME extends InputMethodService
}
private void handleSeparator(int primaryCode) {
+ if (VOICE_INSTALLED && mVoiceInputHighlighted) {
+ commitVoiceInput();
+ }
boolean pickedDefault = false;
// Handle separator
InputConnection ic = getCurrentInputConnection();
@@ -727,12 +1076,12 @@ public class LatinIME extends InputMethodService
}
if (mPredicting) {
// In certain languages where single quote is a separator, it's better
- // not to auto correct, but accept the typed word. For instance,
+ // not to auto correct, but accept the typed word. For instance,
// in Italian dov' should not be expanded to dove' because the elision
// requires the last vowel to be removed.
- if (mAutoCorrectOn && primaryCode != '\'' &&
- (mJustRevertedSeparator == null
- || mJustRevertedSeparator.length() == 0
+ if (mAutoCorrectOn && primaryCode != '\'' &&
+ (mJustRevertedSeparator == null
+ || mJustRevertedSeparator.length() == 0
|| mJustRevertedSeparator.charAt(0) != primaryCode)) {
pickDefaultSuggestion();
pickedDefault = true;
@@ -742,10 +1091,10 @@ public class LatinIME extends InputMethodService
}
sendKeyChar((char)primaryCode);
TextEntryState.typedCharacter((char) primaryCode, true);
- if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED
+ if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED
&& primaryCode != KEYCODE_ENTER) {
swapPunctuationAndSpace();
- } else if (isPredictionOn() && primaryCode == ' ') {
+ } else if (isPredictionOn() && primaryCode == ' ') {
//else if (TextEntryState.STATE_SPACE_AFTER_ACCEPTED) {
doubleSpace();
}
@@ -757,9 +1106,12 @@ public class LatinIME extends InputMethodService
ic.endBatchEdit();
}
}
-
+
private void handleClose() {
commitTyped(getCurrentInputConnection());
+ if (VOICE_INSTALLED & mRecognizing) {
+ mVoiceInput.cancel();
+ }
requestHideSelf(0);
mInputView.closing();
TextEntryState.endSession();
@@ -770,7 +1122,7 @@ public class LatinIME extends InputMethodService
toggleCapsLock();
}
}
-
+
private void toggleCapsLock() {
mCapsLock = !mCapsLock;
if (mKeyboardSwitcher.isAlphabetMode()) {
@@ -782,25 +1134,219 @@ public class LatinIME extends InputMethodService
mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100);
}
-
+
private boolean isPredictionOn() {
boolean predictionOn = mPredictionOn;
//if (isFullscreenMode()) predictionOn &= mPredictionLandscape;
return predictionOn;
}
-
+
private boolean isCandidateStripVisible() {
return isPredictionOn() && mShowSuggestions;
}
+ public void onCancelVoice() {
+ if (mRecognizing) {
+ switchToKeyboardView();
+ }
+ }
+
+ private void switchToKeyboardView() {
+ mHandler.post(new Runnable() {
+ public void run() {
+ mRecognizing = false;
+ if (mInputView != null) {
+ setInputView(mInputView);
+ }
+ updateInputViewShown();
+ }});
+ }
+
+ private void switchToRecognitionStatusView() {
+ mHandler.post(new Runnable() {
+ public void run() {
+ mRecognizing = true;
+ setInputView(mVoiceInput.getView());
+ updateInputViewShown();
+ }});
+ }
+
+ private void startListening(boolean swipe) {
+ if (!mHasUsedVoiceInput ||
+ (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale)) {
+ // Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
+ showVoiceWarningDialog(swipe);
+ } else {
+ reallyStartListening(swipe);
+ }
+ }
+
+ private void reallyStartListening(boolean swipe) {
+ if (!mHasUsedVoiceInput) {
+ // The user has started a voice input, so remember that in the
+ // future (so we don't show the warning dialog after the first run).
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(this).edit();
+ editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
+ editor.commit();
+ mHasUsedVoiceInput = true;
+ }
+
+ if (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale) {
+ // The user has started a voice input from an unsupported locale, so remember that
+ // in the future (so we don't show the warning dialog the next time they do this).
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(this).edit();
+ editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
+ editor.commit();
+ mHasUsedVoiceInputUnsupportedLocale = true;
+ }
+
+ // Clear N-best suggestions
+ setSuggestions(null, false, false, true);
+
+ FieldContext context = new FieldContext(
+ getCurrentInputConnection(),
+ getCurrentInputEditorInfo(),
+ mLanguageSwitcher.getInputLanguage(),
+ mLanguageSwitcher.getEnabledLanguages());
+ mVoiceInput.startListening(context, swipe);
+ switchToRecognitionStatusView();
+ }
+
+ private void showVoiceWarningDialog(final boolean swipe) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setCancelable(true);
+ builder.setIcon(R.drawable.ic_mic_dialog);
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ mVoiceInput.logKeyboardWarningDialogOk();
+ reallyStartListening(swipe);
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ mVoiceInput.logKeyboardWarningDialogCancel();
+ }
+ });
+
+ if (mLocaleSupportedForVoiceInput) {
+ String message = getString(R.string.voice_warning_may_not_understand) + "\n\n" +
+ getString(R.string.voice_warning_how_to_turn_off);
+ builder.setMessage(message);
+ } else {
+ String message = getString(R.string.voice_warning_locale_not_supported) + "\n\n" +
+ getString(R.string.voice_warning_may_not_understand) + "\n\n" +
+ getString(R.string.voice_warning_how_to_turn_off);
+ builder.setMessage(message);
+ }
+
+ builder.setTitle(R.string.voice_warning_title);
+ mVoiceWarningDialog = builder.create();
+
+ Window window = mVoiceWarningDialog.getWindow();
+ WindowManager.LayoutParams lp = window.getAttributes();
+ lp.token = mInputView.getWindowToken();
+ lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+ window.setAttributes(lp);
+ window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+ mVoiceInput.logKeyboardWarningDialogShown();
+ mVoiceWarningDialog.show();
+ }
+
+ public void onVoiceResults(List<String> candidates,
+ Map<String, List<CharSequence>> alternatives) {
+ if (!mRecognizing) {
+ return;
+ }
+ mVoiceResults.candidates = candidates;
+ mVoiceResults.alternatives = alternatives;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_VOICE_RESULTS));
+ }
+
+ private void handleVoiceResults() {
+ mAfterVoiceInput = true;
+ mImmediatelyAfterVoiceInput = true;
+
+ InputConnection ic = getCurrentInputConnection();
+ if (!isFullscreenMode()) {
+ // Start listening for updates to the text from typing, etc.
+ if (ic != null) {
+ ExtractedTextRequest req = new ExtractedTextRequest();
+ ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
+ }
+ }
+
+ vibrate();
+ switchToKeyboardView();
+
+ final List<CharSequence> nBest = new ArrayList<CharSequence>();
+ boolean capitalizeFirstWord = preferCapitalization()
+ || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted());
+ for (String c : mVoiceResults.candidates) {
+ if (capitalizeFirstWord) {
+ c = Character.toUpperCase(c.charAt(0)) + c.substring(1, c.length());
+ }
+ nBest.add(c);
+ }
+
+ if (nBest.size() == 0) {
+ return;
+ }
+
+ String bestResult = nBest.get(0).toString();
+
+ mVoiceInput.logVoiceInputDelivered();
+
+ mHints.registerVoiceResult(bestResult);
+
+ if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
+
+ commitTyped(ic);
+ EditingUtil.appendText(ic, bestResult);
+
+ if (ic != null) ic.endBatchEdit();
+
+ // Show N-Best alternates, if there is more than one choice.
+ if (nBest.size() > 1) {
+ mImmediatelyAfterVoiceSuggestions = true;
+ mShowingVoiceSuggestions = true;
+ setSuggestions(nBest.subList(1, nBest.size()), false, true, true);
+ setCandidatesViewShown(true);
+ }
+ mVoiceInputHighlighted = true;
+ mWordToSuggestions.putAll(mVoiceResults.alternatives);
+
+ }
+
+ private void setSuggestions(
+ List<CharSequence> suggestions,
+ boolean completions,
+
+ boolean typedWordValid,
+ boolean haveMinimalSuggestion) {
+
+ if (mIsShowingHint) {
+ setCandidatesView(mCandidateViewContainer);
+ mIsShowingHint = false;
+ }
+
+ if (mCandidateView != null) {
+ mCandidateView.setSuggestions(
+ suggestions, completions, typedWordValid, haveMinimalSuggestion);
+ }
+ }
+
private void updateSuggestions() {
+ mSuggestionShouldReplaceCurrentWord = false;
+
// Check if we have a suggestion engine attached.
- if (mSuggest == null || !isPredictionOn()) {
+ if ((mSuggest == null || !isPredictionOn()) && !mVoiceInputHighlighted) {
return;
}
-
+
if (!mPredicting) {
- mCandidateView.setSuggestions(null, false, false, false);
+ setNextSuggestions();
return;
}
@@ -809,14 +1355,15 @@ public class LatinIME extends InputMethodService
//|| mCorrectionMode == mSuggest.CORRECTION_FULL;
CharSequence typedWord = mWord.getTypedWord();
// If we're in basic correct
- boolean typedWordValid = mSuggest.isValidWord(typedWord);
+ boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
+ (preferCapitalization() && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
if (mCorrectionMode == Suggest.CORRECTION_FULL) {
correctionAvailable |= typedWordValid;
}
// Don't auto-correct words with multiple capital letter
correctionAvailable &= !mWord.isMostlyCaps();
- mCandidateView.setSuggestions(stringList, false, typedWordValid, correctionAvailable);
+ setSuggestions(stringList, false, typedWordValid, correctionAvailable);
if (stringList.size() > 0) {
if (correctionAvailable && !typedWordValid && stringList.size() > 1) {
mBestWord = stringList.get(1);
@@ -843,6 +1390,8 @@ public class LatinIME extends InputMethodService
}
public void pickSuggestionManually(int index, CharSequence suggestion) {
+ if (mAfterVoiceInput && mShowingVoiceSuggestions) mVoiceInput.logNBestChoose(index);
+
if (mCompletionOn && mCompletions != null && index >= 0
&& index < mCompletions.length) {
CompletionInfo ci = mCompletions[index];
@@ -857,6 +1406,12 @@ public class LatinIME extends InputMethodService
updateShiftKeyState(getCurrentInputEditorInfo());
return;
}
+
+ // If this is a punctuation, apply it through the normal key press
+ if (suggestion.length() == 1 && isWordSeparator(suggestion.charAt(0))) {
+ onKey(suggestion.charAt(0), null);
+ return;
+ }
pickSuggestion(suggestion);
TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
// Follow it with a space
@@ -866,18 +1421,23 @@ public class LatinIME extends InputMethodService
// Fool the state watcher so that a subsequent backspace will not do a revert
TextEntryState.typedCharacter((char) KEYCODE_SPACE, true);
}
-
+
private void pickSuggestion(CharSequence suggestion) {
if (mCapsLock) {
suggestion = suggestion.toString().toUpperCase();
- } else if (preferCapitalization()
+ } else if (preferCapitalization()
|| (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted())) {
suggestion = suggestion.toString().toUpperCase().charAt(0)
+ suggestion.subSequence(1, suggestion.length()).toString();
}
InputConnection ic = getCurrentInputConnection();
if (ic != null) {
- ic.commitText(suggestion, 1);
+ if (mSuggestionShouldReplaceCurrentWord) {
+ EditingUtil.deleteWordAtCursor(ic, getWordSeparators());
+ }
+ if (!VoiceInput.DELETE_SYMBOL.equals(suggestion)) {
+ ic.commitText(suggestion, 1);
+ }
}
// Add the word to the auto dictionary if it's not a known word
if (mAutoDictionary.isValidWord(suggestion) || !mSuggest.isValidWord(suggestion)) {
@@ -885,12 +1445,14 @@ public class LatinIME extends InputMethodService
}
mPredicting = false;
mCommittedLength = suggestion.length();
- if (mCandidateView != null) {
- mCandidateView.setSuggestions(null, false, false, false);
- }
+ setNextSuggestions();
updateShiftKeyState(getCurrentInputEditorInfo());
}
+ private void setNextSuggestions() {
+ setSuggestions(mSuggestPuncList, false, false, false);
+ }
+
private boolean isCursorTouchingWord() {
InputConnection ic = getCurrentInputConnection();
if (ic == null) return false;
@@ -900,13 +1462,13 @@ public class LatinIME extends InputMethodService
&& !isWordSeparator(toLeft.charAt(0))) {
return true;
}
- if (!TextUtils.isEmpty(toRight)
+ if (!TextUtils.isEmpty(toRight)
&& !isWordSeparator(toRight.charAt(0))) {
return true;
}
return false;
}
-
+
public void revertLastWord(boolean deleteChar) {
final int length = mComposing.length();
if (!mPredicting && length > 0) {
@@ -917,7 +1479,7 @@ public class LatinIME extends InputMethodService
if (deleteChar) ic.deleteSurroundingText(1, 0);
int toDelete = mCommittedLength;
CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
- if (toTheLeft != null && toTheLeft.length() > 0
+ if (toTheLeft != null && toTheLeft.length() > 0
&& isWordSeparator(toTheLeft.charAt(0))) {
toDelete--;
}
@@ -935,7 +1497,7 @@ public class LatinIME extends InputMethodService
protected String getWordSeparators() {
return mWordSeparators;
}
-
+
public boolean isWordSeparator(int code) {
String separators = getWordSeparators();
return separators.contains(String.valueOf((char)code));
@@ -956,6 +1518,11 @@ public class LatinIME extends InputMethodService
}
public void swipeRight() {
+ if (userHasNotTypedRecently() && VOICE_INSTALLED && mEnableVoice &&
+ fieldCanDoVoice(makeFieldContext())) {
+ startListening(true /* was a swipe */);
+ }
+
if (LatinKeyboardView.DEBUG_AUTO_PLAY) {
ClipboardManager cm = ((ClipboardManager)getSystemService(CLIPBOARD_SERVICE));
CharSequence text = cm.getText();
@@ -964,9 +1531,36 @@ public class LatinIME extends InputMethodService
}
}
}
-
+
+ private void toggleLanguage(boolean reset, boolean next) {
+ if (reset) {
+ mLanguageSwitcher.reset();
+ } else {
+ if (next) {
+ mLanguageSwitcher.next();
+ } else {
+ mLanguageSwitcher.prev();
+ }
+ }
+ int currentKeyboardMode = mKeyboardSwitcher.getKeyboardMode();
+ reloadKeyboards();
+ mKeyboardSwitcher.makeKeyboards(true);
+ mKeyboardSwitcher.setKeyboardMode(currentKeyboardMode, 0,
+ mEnableVoiceButton && mEnableVoice);
+ initSuggest(mLanguageSwitcher.getInputLanguage());
+ mLanguageSwitcher.persist();
+ updateShiftKeyState(getCurrentInputEditorInfo());
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (PREF_SELECTED_LANGUAGES.equals(key)) {
+ mLanguageSwitcher.loadLocales(sharedPreferences);
+ mRefreshKeyboardRequired = true;
+ }
+ }
+
public void swipeLeft() {
- //handleBackspace();
}
public void swipeDown() {
@@ -983,9 +1577,37 @@ public class LatinIME extends InputMethodService
}
public void onRelease(int primaryCode) {
+ // Reset any drag flags in the keyboard
+ ((LatinKeyboard) mInputView.getKeyboard()).keyReleased();
//vibrate();
}
+ private FieldContext makeFieldContext() {
+ return new FieldContext(
+ getCurrentInputConnection(),
+ getCurrentInputEditorInfo(),
+ mLanguageSwitcher.getInputLanguage(),
+ mLanguageSwitcher.getEnabledLanguages());
+ }
+
+ private boolean fieldCanDoVoice(FieldContext fieldContext) {
+ return !mPasswordText
+ && mVoiceInput != null
+ && !mVoiceInput.isBlacklistedField(fieldContext);
+ }
+
+ private boolean fieldIsRecommendedForVoice(FieldContext fieldContext) {
+ // TODO: Move this logic into the VoiceInput method.
+ return !mPasswordText && !mEmailText && mVoiceInput.isRecommendedField(fieldContext);
+ }
+
+ private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) {
+ return ENABLE_VOICE_BUTTON
+ && fieldCanDoVoice(fieldContext)
+ && !(attribute != null && attribute.privateImeOptions != null
+ && attribute.privateImeOptions.equals(IME_OPTION_NO_MICROPHONE));
+ }
+
// receive ringer mode changes to detect silent mode
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -1004,6 +1626,26 @@ public class LatinIME extends InputMethodService
}
}
+ private boolean userHasNotTypedRecently() {
+ return (SystemClock.uptimeMillis() - mLastKeyTime)
+ > MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE;
+ }
+
+ /*
+ * Only trigger a swipe action if the user hasn't typed X millis before
+ * now, and if they don't type Y millis after the swipe is detected. This
+ * delays the onset of the swipe action by Y millis.
+ */
+ private void conservativelyTriggerSwipeAction(final Runnable action) {
+ if (userHasNotTypedRecently()) {
+ mSwipeTriggerTimeMillis = System.currentTimeMillis();
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_START_LISTENING_AFTER_SWIPE),
+ MIN_MILLIS_AFTER_SWIPE_TO_WAIT_FOR_TYPING);
+ }
+ }
+
+
private void playKeyClick(int primaryCode) {
// if mAudioManager is null, we don't have the ringer state yet
// mAudioManager will be set by updateRingerMode
@@ -1053,7 +1695,7 @@ public class LatinIME extends InputMethodService
}
}
}
-
+
private void startTutorial() {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_TUTORIAL), 500);
}
@@ -1067,10 +1709,26 @@ public class LatinIME extends InputMethodService
mUserDictionary.addWord(word, frequency);
}
- private void launchSettings() {
+ private void updateCorrectionMode() {
+ mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
+ mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
+ && !mInputTypeNoAutoCorrect && mHasDictionary;
+ mCorrectionMode = mAutoCorrectOn
+ ? Suggest.CORRECTION_FULL
+ : (mQuickFixes ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
+ if (mSuggest != null) {
+ mSuggest.setCorrectionMode(mCorrectionMode);
+ }
+ }
+
+ protected void launchSettings() {
+ launchSettings(LatinIMESettings.class);
+ }
+
+ protected void launchSettings(Class settingsClass) {
handleClose();
Intent intent = new Intent();
- intent.setClass(LatinIME.this, LatinIMESettings.class);
+ intent.setClass(LatinIME.this, settingsClass);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
@@ -1082,16 +1740,64 @@ public class LatinIME extends InputMethodService
mSoundOn = sp.getBoolean(PREF_SOUND_ON, false);
mAutoCap = sp.getBoolean(PREF_AUTO_CAP, true);
mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true);
+ mHasUsedVoiceInput = sp.getBoolean(PREF_HAS_USED_VOICE_INPUT, false);
+ mHasUsedVoiceInputUnsupportedLocale =
+ sp.getBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, false);
+
+ // Get the current list of supported locales and check the current locale against that
+ // list. We cache this value so as not to check it every time the user starts a voice
+ // input. Because this method is called by onStartInputView, this should mean that as
+ // long as the locale doesn't change while the user is keeping the IME open, the
+ // value should never be stale.
+ String supportedLocalesString = SettingsUtil.getSettingsString(
+ getContentResolver(),
+ SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
+ DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
+ ArrayList<String> voiceInputSupportedLocales =
+ Lists.newArrayList(supportedLocalesString.split("\\s+"));
+
+ mLocaleSupportedForVoiceInput = voiceInputSupportedLocales.contains(mLocale);
+
// If there is no auto text data, then quickfix is forced to "on", so that the other options
// will continue to work
+
if (AutoText.getSize(mInputView) < 1) mQuickFixes = true;
mShowSuggestions = sp.getBoolean(PREF_SHOW_SUGGESTIONS, true) & mQuickFixes;
- boolean autoComplete = sp.getBoolean(PREF_AUTO_COMPLETE,
- getResources().getBoolean(R.bool.enable_autocorrect)) & mShowSuggestions;
- mAutoCorrectOn = mSuggest != null && (autoComplete || mQuickFixes);
- mCorrectionMode = autoComplete
- ? Suggest.CORRECTION_FULL
- : (mQuickFixes ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
+
+ if (VOICE_INSTALLED) {
+ boolean enableVoice = sp.getBoolean(PREF_ENABLE_VOICE, true);
+ boolean voiceOnPrimary = sp.getBoolean(PREF_VOICE_MAIN, true);
+ if (mKeyboardSwitcher != null &&
+ (enableVoice != mEnableVoice || voiceOnPrimary != mVoiceOnPrimary)) {
+ mKeyboardSwitcher.setVoiceMode(enableVoice, voiceOnPrimary);
+ }
+ mEnableVoice = enableVoice;
+ mVoiceOnPrimary = voiceOnPrimary;
+ }
+ mAutoCorrectEnabled = sp.getBoolean(PREF_AUTO_COMPLETE,
+ mResources.getBoolean(R.bool.enable_autocorrect)) & mShowSuggestions;
+ updateCorrectionMode();
+ mLanguageSwitcher.loadLocales(sp);
+ }
+
+ private String getPersistedInputLanguage() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ return sp.getString(PREF_INPUT_LANGUAGE, null);
+ }
+
+ private String getSelectedInputLanguages() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ return sp.getString(PREF_SELECTED_LANGUAGES, null);
+ }
+
+ private void initSuggestPuncList() {
+ mSuggestPuncList = new ArrayList<CharSequence>();
+ String suggestPuncs = mResources.getString(R.string.suggested_punctuations);
+ if (suggestPuncs != null) {
+ for (int i = 0; i < suggestPuncs.length(); i++) {
+ mSuggestPuncList.add(suggestPuncs.subSequence(i, i + 1));
+ }
+ }
}
private void showOptionsMenu() {
@@ -1100,7 +1806,7 @@ public class LatinIME extends InputMethodService
builder.setIcon(R.drawable.ic_dialog_keyboard);
builder.setNegativeButton(android.R.string.cancel, null);
CharSequence itemSettings = getString(R.string.english_ime_settings);
- CharSequence itemInputMethod = getString(com.android.internal.R.string.inputMethod);
+ CharSequence itemInputMethod = getString(R.string.inputMethod);
builder.setItems(new CharSequence[] {
itemSettings, itemInputMethod},
new DialogInterface.OnClickListener() {
@@ -1118,7 +1824,7 @@ public class LatinIME extends InputMethodService
}
}
});
- builder.setTitle(getResources().getString(R.string.english_ime_name));
+ builder.setTitle(mResources.getString(R.string.english_ime_name));
mOptionsDialog = builder.create();
Window window = mOptionsDialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
@@ -1137,10 +1843,10 @@ public class LatinIME extends InputMethodService
updateShiftKeyState(getCurrentInputEditorInfo());
}
-
+
@Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
super.dump(fd, fout, args);
-
+
final Printer p = new PrintWriterPrinter(fout);
p.println("LatinIME state :");
p.println(" Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
@@ -1158,13 +1864,14 @@ public class LatinIME extends InputMethodService
}
// Characters per second measurement
-
+
private static final boolean PERF_DEBUG = false;
private long mLastCpsTime;
private static final int CPS_BUFFER_SIZE = 16;
private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
private int mCpsIndex;
-
+ private boolean mInputTypeNoAutoCorrect;
+
private void measureCps() {
if (!LatinIME.PERF_DEBUG) return;
long now = System.currentTimeMillis();
@@ -1181,7 +1888,7 @@ public class LatinIME extends InputMethodService
// If the user touches a typed word 2 times or more, it will become valid.
private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED;
// If the user touches a typed word 5 times or more, it will be added to the user dict.
- private static final int PROMOTION_THRESHOLD = 5 * FREQUENCY_FOR_PICKED;
+ private static final int PROMOTION_THRESHOLD = 4 * FREQUENCY_FOR_PICKED;
public AutoDictionary(Context context) {
super(context);
@@ -1190,7 +1897,7 @@ public class LatinIME extends InputMethodService
@Override
public boolean isValidWord(CharSequence word) {
final int frequency = getWordFrequency(word);
- return frequency > VALIDITY_THRESHOLD;
+ return frequency >= VALIDITY_THRESHOLD;
}
@Override
@@ -1198,14 +1905,17 @@ public class LatinIME extends InputMethodService
final int length = word.length();
// Don't add very short or very long words.
if (length < 2 || length > getMaxWordLength()) return;
- super.addWord(word, addFrequency);
- final int freq = getWordFrequency(word);
- if (freq > PROMOTION_THRESHOLD) {
+ if (mWord.isAutoCapitalized()) {
+ // Remove caps before adding
+ word = Character.toLowerCase(word.charAt(0))
+ + word.substring(1);
+ }
+ int freq = getWordFrequency(word);
+ freq = freq < 0 ? addFrequency : freq + addFrequency;
+ super.addWord(word, freq);
+ if (freq >= PROMOTION_THRESHOLD) {
LatinIME.this.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD);
}
}
}
}
-
-
-
diff --git a/src/com/android/inputmethod/latin/LatinIMEBackupAgent.java b/src/com/android/inputmethod/latin/LatinIMEBackupAgent.java
index c454f120e..b6a800ebd 100644
--- a/src/com/android/inputmethod/latin/LatinIMEBackupAgent.java
+++ b/src/com/android/inputmethod/latin/LatinIMEBackupAgent.java
@@ -26,6 +26,6 @@ public class LatinIMEBackupAgent extends BackupHelperAgent {
public void onCreate() {
addHelper("shared_pref", new SharedPreferencesBackupHelper(this,
- "com.android.inputmethod.latin_preferences"));
+ getPackageName() + "_preferences"));
}
}
diff --git a/src/com/android/inputmethod/latin/LatinIMESettings.java b/src/com/android/inputmethod/latin/LatinIMESettings.java
index c8ea309e3..98a0af9d1 100644
--- a/src/com/android/inputmethod/latin/LatinIMESettings.java
+++ b/src/com/android/inputmethod/latin/LatinIMESettings.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2008-2009 Google Inc.
- *
+ *
* 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
@@ -16,32 +16,69 @@
package com.android.inputmethod.latin;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.backup.BackupManager;
+import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
+import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.speech.RecognitionManager;
import android.text.AutoText;
+import android.util.Log;
+
+import com.google.android.collect.Lists;
+
+import com.android.inputmethod.voice.SettingsUtil;
+import com.android.inputmethod.voice.VoiceInputLogger;
+
+import java.util.ArrayList;
+import java.util.Locale;
public class LatinIMESettings extends PreferenceActivity
- implements SharedPreferences.OnSharedPreferenceChangeListener {
+ implements SharedPreferences.OnSharedPreferenceChangeListener,
+ OnPreferenceClickListener,
+ DialogInterface.OnDismissListener {
private static final String QUICK_FIXES_KEY = "quick_fixes";
private static final String SHOW_SUGGESTIONS_KEY = "show_suggestions";
private static final String PREDICTION_SETTINGS_KEY = "prediction_settings";
-
+ private static final String VOICE_SETTINGS_KEY = "enable_voice_input";
+ private static final String VOICE_SERVER_KEY = "voice_server_url";
+
+ private static final String TAG = "LatinIMESettings";
+
+ // Dialog ids
+ private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
+
private CheckBoxPreference mQuickFixes;
private CheckBoxPreference mShowSuggestions;
-
+ private CheckBoxPreference mVoicePreference;
+
+ private VoiceInputLogger mLogger;
+
+ private boolean mOkClicked = false;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.prefs);
mQuickFixes = (CheckBoxPreference) findPreference(QUICK_FIXES_KEY);
mShowSuggestions = (CheckBoxPreference) findPreference(SHOW_SUGGESTIONS_KEY);
- getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(
- this);
+ mVoicePreference = (CheckBoxPreference) findPreference(VOICE_SETTINGS_KEY);
+
+ SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ prefs.registerOnSharedPreferenceChangeListener(this);
+
+ mVoicePreference.setOnPreferenceClickListener(this);
+ mVoicePreference.setChecked(prefs.getBoolean(
+ VOICE_SETTINGS_KEY, getResources().getBoolean(R.bool.voice_input_default)));
+
+ mLogger = VoiceInputLogger.getLogger(this);
}
@Override
@@ -50,10 +87,17 @@ public class LatinIMESettings extends PreferenceActivity
int autoTextSize = AutoText.getSize(getListView());
if (autoTextSize < 1) {
((PreferenceGroup) findPreference(PREDICTION_SETTINGS_KEY))
- .removePreference(mQuickFixes);
+ .removePreference(mQuickFixes);
} else {
mShowSuggestions.setDependency(QUICK_FIXES_KEY);
}
+ if (!LatinIME.VOICE_INSTALLED
+ || !RecognitionManager.isRecognitionAvailable(this)) {
+ getPreferenceScreen().removePreference(mVoicePreference);
+ }
+
+ mVoicePreference.setChecked(
+ getPreferenceManager().getSharedPreferences().getBoolean(VOICE_SETTINGS_KEY, true));
}
@Override
@@ -67,4 +111,91 @@ public class LatinIMESettings extends PreferenceActivity
String key) {
(new BackupManager(this)).dataChanged();
}
+
+ public boolean onPreferenceClick(Preference preference) {
+ if (preference == mVoicePreference) {
+ if (mVoicePreference.isChecked()) {
+ mOkClicked = false;
+ showDialog(VOICE_INPUT_CONFIRM_DIALOG);
+ } else {
+ updateVoicePreference();
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case VOICE_INPUT_CONFIRM_DIALOG:
+ DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
+ mVoicePreference.setChecked(false);
+ mLogger.settingsWarningDialogCancel();
+ } else if (whichButton == DialogInterface.BUTTON_POSITIVE) {
+ mOkClicked = true;
+ mLogger.settingsWarningDialogOk();
+ }
+ updateVoicePreference();
+ }
+ };
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.voice_warning_title)
+ .setPositiveButton(android.R.string.ok, listener)
+ .setNegativeButton(android.R.string.cancel, listener);
+
+ // Get the current list of supported locales and check the current locale against
+ // that list, to decide whether to put a warning that voice input will not work in
+ // the current language as part of the pop-up confirmation dialog.
+ String supportedLocalesString = SettingsUtil.getSettingsString(
+ getContentResolver(),
+ SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
+ LatinIME.DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
+ ArrayList<String> voiceInputSupportedLocales =
+ Lists.newArrayList(supportedLocalesString.split("\\s+"));
+ boolean localeSupported = voiceInputSupportedLocales.contains(
+ Locale.getDefault().toString());
+
+ if (localeSupported) {
+ String message = getString(R.string.voice_warning_may_not_understand) + "\n\n" +
+ getString(R.string.voice_hint_dialog_message);
+ builder.setMessage(message);
+ } else {
+ String message = getString(R.string.voice_warning_locale_not_supported) +
+ "\n\n" + getString(R.string.voice_warning_may_not_understand) + "\n\n" +
+ getString(R.string.voice_hint_dialog_message);
+ builder.setMessage(message);
+ }
+
+ AlertDialog dialog = builder.create();
+ dialog.setOnDismissListener(this);
+ mLogger.settingsWarningDialogShown();
+ return dialog;
+ default:
+ Log.e(TAG, "unknown dialog " + id);
+ return null;
+ }
+ }
+
+ public void onDismiss(DialogInterface dialog) {
+ mLogger.settingsWarningDialogDismissed();
+ if (!mOkClicked) {
+ // This assumes that onPreferenceClick gets called first, and this if the user
+ // agreed after the warning, we set the mOkClicked value to true.
+ mVoicePreference.setChecked(false);
+ }
+ }
+
+ private void updateVoicePreference() {
+ SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
+ boolean isChecked = mVoicePreference.isChecked();
+ if (isChecked) {
+ mLogger.voiceInputSettingEnabled();
+ } else {
+ mLogger.voiceInputSettingDisabled();
+ }
+ editor.putBoolean(VOICE_SETTINGS_KEY, isChecked);
+ editor.commit();
+ }
}
diff --git a/src/com/android/inputmethod/latin/LatinKeyboard.java b/src/com/android/inputmethod/latin/LatinKeyboard.java
index 9b04aa264..27c409a03 100644
--- a/src/com/android/inputmethod/latin/LatinKeyboard.java
+++ b/src/com/android/inputmethod/latin/LatinKeyboard.java
@@ -16,11 +16,26 @@
package com.android.inputmethod.latin;
+import java.util.List;
+import java.util.Locale;
+
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.Paint.Align;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard;
+import android.text.TextPaint;
+import android.view.ViewConfiguration;
import android.view.inputmethod.EditorInfo;
public class LatinKeyboard extends Keyboard {
@@ -29,8 +44,33 @@ public class LatinKeyboard extends Keyboard {
private Drawable mShiftLockPreviewIcon;
private Drawable mOldShiftIcon;
private Drawable mOldShiftPreviewIcon;
+ private Drawable mSpaceIcon;
+ private Drawable mSpacePreviewIcon;
+ private Drawable mMicIcon;
+ private Drawable mMicPreviewIcon;
+ private Drawable m123MicIcon;
+ private Drawable m123MicPreviewIcon;
+ private Drawable mButtonArrowLeftIcon;
+ private Drawable mButtonArrowRightIcon;
private Key mShiftKey;
private Key mEnterKey;
+ private Key mF1Key;
+ private Key mSpaceKey;
+ private Key m123Key;
+ private int mSpaceKeyIndex = -1;
+ private int mSpaceDragStartX;
+ private int mSpaceDragLastDiff;
+ /* package */ Locale mLocale;
+ private LanguageSwitcher mLanguageSwitcher;
+ private Resources mRes;
+ private Context mContext;
+ private int mMode;
+ private boolean mHasVoice;
+ private boolean mCurrentlyInSpace;
+ private SlidingLocaleDrawable mSlidingLocaleIcon;
+ private Rect mBounds = new Rect();
+
+ private int mExtensionResId;
private static final int SHIFT_OFF = 0;
private static final int SHIFT_ON = 1;
@@ -38,22 +78,40 @@ public class LatinKeyboard extends Keyboard {
private int mShiftState = SHIFT_OFF;
+ private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f;
+
static int sSpacebarVerticalCorrection;
public LatinKeyboard(Context context, int xmlLayoutResId) {
- this(context, xmlLayoutResId, 0);
+ this(context, xmlLayoutResId, 0, false);
}
- public LatinKeyboard(Context context, int xmlLayoutResId, int mode) {
+ public LatinKeyboard(Context context, int xmlLayoutResId, int mode, boolean hasVoice) {
super(context, xmlLayoutResId, mode);
- Resources res = context.getResources();
+ final Resources res = context.getResources();
+ mContext = context;
+ mMode = mode;
+ mRes = res;
+ mHasVoice = hasVoice;
mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked);
mShiftLockPreviewIcon.setBounds(0, 0,
mShiftLockPreviewIcon.getIntrinsicWidth(),
mShiftLockPreviewIcon.getIntrinsicHeight());
+ mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space);
+ mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space);
+ mMicIcon = res.getDrawable(R.drawable.sym_keyboard_mic);
+ mMicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_mic);
+ setDefaultBounds(mMicPreviewIcon);
+ mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left);
+ mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right);
+ m123MicIcon = res.getDrawable(R.drawable.sym_keyboard_123_mic);
+ m123MicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_123_mic);
+ setDefaultBounds(m123MicPreviewIcon);
sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
R.dimen.spacebar_vertical_correction);
+ setF1Key(xmlLayoutResId == R.xml.kbd_qwerty);
+ mSpaceKeyIndex = indexOf((int) ' ');
}
public LatinKeyboard(Context context, int layoutTemplateResId,
@@ -65,12 +123,23 @@ public class LatinKeyboard extends Keyboard {
protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
XmlResourceParser parser) {
Key key = new LatinKey(res, parent, x, y, parser);
- if (key.codes[0] == 10) {
+ switch (key.codes[0]) {
+ case 10:
mEnterKey = key;
+ break;
+ case LatinKeyboardView.KEYCODE_F1:
+ mF1Key = key;
+ break;
+ case 32:
+ mSpaceKey = key;
+ break;
+ case KEYCODE_MODE_CHANGE:
+ m123Key = key;
+ break;
}
return key;
}
-
+
void setImeOptions(Resources res, int mode, int options) {
if (mEnterKey != null) {
// Reset some of the rarely used attributes.
@@ -181,7 +250,7 @@ public class LatinKeyboard extends Keyboard {
}
return shiftChanged;
}
-
+
@Override
public boolean isShifted() {
if (mShiftKey != null) {
@@ -191,7 +260,220 @@ public class LatinKeyboard extends Keyboard {
}
}
- static class LatinKey extends Keyboard.Key {
+ public void setExtension(int resId) {
+ mExtensionResId = resId;
+ }
+
+ public int getExtension() {
+ return mExtensionResId;
+ }
+
+ private void setDefaultBounds(Drawable drawable) {
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+ }
+
+ private void setF1Key(boolean isAlphaKeyboard) {
+ if (mF1Key == null) return;
+ if (!mHasVoice) {
+ mF1Key.label = ",";
+ mF1Key.codes = new int[] { ',' };
+ mF1Key.icon = null;
+ mF1Key.iconPreview = null;
+ if (isAlphaKeyboard && m123Key != null) {
+ m123Key.icon = m123MicIcon;
+ m123Key.iconPreview = m123MicPreviewIcon;
+ m123Key.label = null;
+ }
+ } else {
+ mF1Key.codes = new int[] { LatinKeyboardView.KEYCODE_VOICE };
+ mF1Key.label = null;
+ mF1Key.icon = mMicIcon;
+ mF1Key.iconPreview = mMicPreviewIcon;
+ }
+ }
+
+ private void updateSpaceBarForLocale() {
+ if (mLocale != null) {
+ // Create the graphic for spacebar
+ Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(buffer);
+ canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ // Get the text size from the theme
+ paint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14));
+ paint.setTextAlign(Align.CENTER);
+ // Draw a drop shadow for the text
+ paint.setShadowLayer(2f, 0, 0, 0xFF000000);
+ paint.setColor(0xFF808080);
+ final String language = getInputLanguage(mSpaceKey.width, paint);
+ final int ascent = (int) -paint.ascent();
+ canvas.drawText(language,
+ buffer.getWidth() / 2, ascent, paint);
+ // Put arrows on either side of the text
+ if (mLanguageSwitcher.getLocaleCount() > 1) {
+ Rect bounds = new Rect();
+ paint.getTextBounds(language, 0, language.length(), bounds);
+ drawButtonArrow(mButtonArrowLeftIcon, canvas,
+ (mSpaceKey.width - bounds.right) / 2
+ - mButtonArrowLeftIcon.getIntrinsicWidth(),
+ (int) paint.getTextSize());
+ drawButtonArrow(mButtonArrowRightIcon, canvas,
+ (mSpaceKey.width + bounds.right) / 2, (int) paint.getTextSize());
+ }
+ // Draw the spacebar icon at the bottom
+ int x = (buffer.getWidth() - mSpaceIcon.getIntrinsicWidth()) / 2;
+ int y = buffer.getHeight() - mSpaceIcon.getIntrinsicHeight();
+ mSpaceIcon.setBounds(x, y,
+ x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight());
+ mSpaceIcon.draw(canvas);
+ mSpaceKey.icon = new BitmapDrawable(mRes, buffer);
+ mSpaceKey.repeatable = mLanguageSwitcher.getLocaleCount() < 2;
+ } else {
+ mSpaceKey.icon = mRes.getDrawable(R.drawable.sym_keyboard_space);
+ mSpaceKey.repeatable = true;
+ }
+ }
+
+ private void drawButtonArrow(Drawable arrow, Canvas canvas, int x, int bottomY) {
+ arrow.setBounds(x, bottomY - arrow.getIntrinsicHeight(), x + arrow.getIntrinsicWidth(),
+ bottomY);
+ arrow.draw(canvas);
+ }
+
+ private String getInputLanguage(int widthAvail, Paint paint) {
+ return chooseDisplayName(mLanguageSwitcher.getInputLocale(), widthAvail, paint);
+ }
+
+ private String getNextInputLanguage(int widthAvail, Paint paint) {
+ return chooseDisplayName(mLanguageSwitcher.getNextInputLocale(), widthAvail, paint);
+ }
+
+ private String getPrevInputLanguage(int widthAvail, Paint paint) {
+ return chooseDisplayName(mLanguageSwitcher.getPrevInputLocale(), widthAvail, paint);
+ }
+
+ private String chooseDisplayName(Locale locale, int widthAvail, Paint paint) {
+ if (widthAvail < (int) (.35 * getMinWidth())) {
+ return locale.getLanguage().substring(0, 2).toUpperCase(locale);
+ } else {
+ return locale.getDisplayLanguage(locale);
+ }
+ }
+
+ private void updateLocaleDrag(int diff) {
+ if (mSlidingLocaleIcon == null) {
+ mSlidingLocaleIcon = new SlidingLocaleDrawable(mSpacePreviewIcon, mSpaceKey.width,
+ mSpacePreviewIcon.getIntrinsicHeight());
+ mSlidingLocaleIcon.setBounds(0, 0, mSpaceKey.width,
+ mSpacePreviewIcon.getIntrinsicHeight());
+ mSpaceKey.iconPreview = mSlidingLocaleIcon;
+ }
+ mSlidingLocaleIcon.setDiff(diff);
+ if (Math.abs(diff) == Integer.MAX_VALUE) {
+ mSpaceKey.iconPreview = mSpacePreviewIcon;
+ } else {
+ mSpaceKey.iconPreview = mSlidingLocaleIcon;
+ }
+ mSpaceKey.iconPreview.invalidateSelf();
+ }
+
+ public int getLanguageChangeDirection() {
+ if (mSpaceKey == null || mLanguageSwitcher.getLocaleCount() < 2
+ || Math.abs(mSpaceDragLastDiff) < mSpaceKey.width * SPACEBAR_DRAG_THRESHOLD ) {
+ return 0; // No change
+ }
+ return mSpaceDragLastDiff > 0 ? 1 : -1;
+ }
+
+ public void setLanguageSwitcher(LanguageSwitcher switcher) {
+ mLanguageSwitcher = switcher;
+ Locale locale = mLanguageSwitcher.getLocaleCount() > 0
+ ? mLanguageSwitcher.getInputLocale()
+ : null;
+ if (mLocale != null && mLocale.equals(locale)) return;
+ mLocale = locale;
+ updateSpaceBarForLocale();
+ }
+
+ boolean isCurrentlyInSpace() {
+ return mCurrentlyInSpace;
+ }
+
+ void keyReleased() {
+ mCurrentlyInSpace = false;
+ mSpaceDragLastDiff = 0;
+ if (mSpaceKey != null) {
+ updateLocaleDrag(Integer.MAX_VALUE);
+ }
+ }
+
+ /**
+ * Does the magic of locking the touch gesture into the spacebar when
+ * switching input languages.
+ */
+ boolean isInside(LatinKey key, int x, int y) {
+ final int code = key.codes[0];
+ if (code == KEYCODE_SHIFT ||
+ code == KEYCODE_DELETE) {
+ y -= key.height / 10;
+ if (code == KEYCODE_SHIFT) x += key.width / 6;
+ if (code == KEYCODE_DELETE) x -= key.width / 6;
+ } else if (code == LatinIME.KEYCODE_SPACE) {
+ y += LatinKeyboard.sSpacebarVerticalCorrection;
+ if (mLanguageSwitcher.getLocaleCount() > 1) {
+ if (mCurrentlyInSpace) {
+ int diff = x - mSpaceDragStartX;
+ if (Math.abs(diff - mSpaceDragLastDiff) > 0) {
+ updateLocaleDrag(diff);
+ }
+ mSpaceDragLastDiff = diff;
+ return true;
+ } else {
+ boolean insideSpace = key.isInsideSuper(x, y);
+ if (insideSpace) {
+ mCurrentlyInSpace = true;
+ mSpaceDragStartX = x;
+ updateLocaleDrag(0);
+ }
+ return insideSpace;
+ }
+ }
+ }
+
+ // Lock into the spacebar
+ if (mCurrentlyInSpace) return false;
+
+ return key.isInsideSuper(x, y);
+ }
+
+ @Override
+ public int[] getNearestKeys(int x, int y) {
+ if (mCurrentlyInSpace) {
+ return new int[] { mSpaceKeyIndex };
+ } else {
+ return super.getNearestKeys(x, y);
+ }
+ }
+
+ private int indexOf(int code) {
+ List<Key> keys = getKeys();
+ int count = keys.size();
+ for (int i = 0; i < count; i++) {
+ if (keys.get(i).codes[0] == code) return i;
+ }
+ return -1;
+ }
+
+ private int getTextSizeFromTheme(int style, int defValue) {
+ TypedArray array = mContext.getTheme().obtainStyledAttributes(
+ style, new int[] { android.R.attr.textSize });
+ int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
+ return textSize;
+ }
+
+ class LatinKey extends Keyboard.Key {
private boolean mShiftLockEnabled;
@@ -222,16 +504,125 @@ public class LatinKeyboard extends Keyboard {
*/
@Override
public boolean isInside(int x, int y) {
- final int code = codes[0];
- if (code == KEYCODE_SHIFT ||
- code == KEYCODE_DELETE) {
- y -= height / 10;
- if (code == KEYCODE_SHIFT) x += width / 6;
- if (code == KEYCODE_DELETE) x -= width / 6;
- } else if (code == LatinIME.KEYCODE_SPACE) {
- y += LatinKeyboard.sSpacebarVerticalCorrection;
- }
+ return LatinKeyboard.this.isInside(this, x, y);
+ }
+
+ boolean isInsideSuper(int x, int y) {
return super.isInside(x, y);
}
}
+
+ /**
+ * Animation to be displayed on the spacebar preview popup when switching
+ * languages by swiping the spacebar. It draws the current, previous and
+ * next languages and moves them by the delta of touch movement on the spacebar.
+ */
+ class SlidingLocaleDrawable extends Drawable {
+
+ private int mWidth;
+ private int mHeight;
+ private Drawable mBackground;
+ private int mDiff;
+ private TextPaint mTextPaint;
+ private int mMiddleX;
+ private int mAscent;
+ private Drawable mLeftDrawable;
+ private Drawable mRightDrawable;
+ private boolean mHitThreshold;
+ private int mThreshold;
+ private String mCurrentLanguage;
+ private String mNextLanguage;
+ private String mPrevLanguage;
+
+ public SlidingLocaleDrawable(Drawable background, int width, int height) {
+ mBackground = background;
+ mBackground.setBounds(0, 0,
+ mBackground.getIntrinsicWidth(), mBackground.getIntrinsicHeight());
+ mWidth = width;
+ mHeight = height;
+ mTextPaint = new TextPaint();
+ int textSize = getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18);
+ mTextPaint.setTextSize(textSize);
+ mTextPaint.setColor(0);
+ mTextPaint.setTextAlign(Align.CENTER);
+ mTextPaint.setAlpha(255);
+ mTextPaint.setAntiAlias(true);
+ mAscent = (int) mTextPaint.ascent();
+ mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2;
+ mLeftDrawable =
+ mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_left);
+ mRightDrawable =
+ mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_right);
+ mLeftDrawable.setBounds(0, 0,
+ mLeftDrawable.getIntrinsicWidth(), mLeftDrawable.getIntrinsicHeight());
+ mRightDrawable.setBounds(mWidth - mRightDrawable.getIntrinsicWidth(), 0,
+ mWidth, mRightDrawable.getIntrinsicHeight());
+ mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ }
+
+ void setDiff(int diff) {
+ if (diff == Integer.MAX_VALUE) {
+ mHitThreshold = false;
+ mCurrentLanguage = null;
+ return;
+ }
+ mDiff = diff;
+ if (mDiff > mWidth) mDiff = mWidth;
+ if (mDiff < -mWidth) mDiff = -mWidth;
+ if (Math.abs(mDiff) > mThreshold) mHitThreshold = true;
+ invalidateSelf();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.save();
+ if (mHitThreshold) {
+ mTextPaint.setColor(0xFF000000);
+ canvas.clipRect(0, 0, mWidth, mHeight);
+ if (mCurrentLanguage == null) {
+ mCurrentLanguage = getInputLanguage(mWidth, mTextPaint);
+ mNextLanguage = getNextInputLanguage(mWidth, mTextPaint);
+ mPrevLanguage = getPrevInputLanguage(mWidth, mTextPaint);
+ }
+ canvas.drawText(mCurrentLanguage,
+ mWidth / 2 + mDiff, -mAscent + 4, mTextPaint);
+ canvas.drawText(mNextLanguage,
+ mDiff - mWidth / 2, -mAscent + 4, mTextPaint);
+ canvas.drawText(mPrevLanguage,
+ mDiff + mWidth + mWidth / 2, -mAscent + 4, mTextPaint);
+ mLeftDrawable.draw(canvas);
+ mRightDrawable.draw(canvas);
+ }
+ if (mBackground != null) {
+ canvas.translate(mMiddleX, 0);
+ mBackground.draw(canvas);
+ }
+ canvas.restore();
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ // Ignore
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ // Ignore
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeight;
+ }
+ }
}
diff --git a/src/com/android/inputmethod/latin/LatinKeyboardView.java b/src/com/android/inputmethod/latin/LatinKeyboardView.java
index d9ff0aa8c..05f8aff36 100644
--- a/src/com/android/inputmethod/latin/LatinKeyboardView.java
+++ b/src/com/android/inputmethod/latin/LatinKeyboardView.java
@@ -16,6 +16,8 @@
package com.android.inputmethod.latin;
+import java.util.List;
+
import android.content.Context;
import android.graphics.Canvas;
import android.inputmethodservice.Keyboard;
@@ -25,17 +27,26 @@ import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
-
-import java.util.List;
+import android.widget.PopupWindow;
public class LatinKeyboardView extends KeyboardView {
static final int KEYCODE_OPTIONS = -100;
static final int KEYCODE_SHIFT_LONGPRESS = -101;
+ static final int KEYCODE_VOICE = -102;
+ static final int KEYCODE_F1 = -103;
+ static final int KEYCODE_NEXT_LANGUAGE = -104;
+ static final int KEYCODE_PREV_LANGUAGE = -105;
private Keyboard mPhoneKeyboard;
+ private boolean mExtensionVisible;
+ private LatinKeyboardView mExtension;
+ private PopupWindow mExtensionPopup;
+ private boolean mFirstEvent;
+
public LatinKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -66,7 +77,129 @@ public class LatinKeyboardView extends KeyboardView {
}
}
-
+ @Override
+ public boolean onTouchEvent(MotionEvent me) {
+ LatinKeyboard keyboard = (LatinKeyboard) getKeyboard();
+ // Reset any bounding box controls in the keyboard
+ if (me.getAction() == MotionEvent.ACTION_DOWN) {
+ keyboard.keyReleased();
+ }
+
+ if (me.getAction() == MotionEvent.ACTION_UP) {
+ int languageDirection = keyboard.getLanguageChangeDirection();
+ if (languageDirection != 0) {
+ getOnKeyboardActionListener().onKey(
+ languageDirection == 1 ? KEYCODE_NEXT_LANGUAGE : KEYCODE_PREV_LANGUAGE,
+ null);
+ me.setAction(MotionEvent.ACTION_CANCEL);
+ keyboard.keyReleased();
+ return super.onTouchEvent(me);
+ }
+ }
+
+ // If we don't have an extension keyboard, don't go any further.
+ if (keyboard.getExtension() == 0) {
+ return super.onTouchEvent(me);
+ }
+ if (me.getY() < 0) {
+ if (mExtensionVisible) {
+ int action = me.getAction();
+ if (mFirstEvent) action = MotionEvent.ACTION_DOWN;
+ mFirstEvent = false;
+ MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(),
+ action,
+ me.getX(), me.getY() + mExtension.getHeight(), me.getMetaState());
+ boolean result = mExtension.onTouchEvent(translated);
+ translated.recycle();
+ if (me.getAction() == MotionEvent.ACTION_UP
+ || me.getAction() == MotionEvent.ACTION_CANCEL) {
+ closeExtension();
+ }
+ return result;
+ } else {
+ if (openExtension()) {
+ MotionEvent cancel = MotionEvent.obtain(me.getDownTime(), me.getEventTime(),
+ MotionEvent.ACTION_CANCEL, me.getX() - 100, me.getY() - 100, 0);
+ super.onTouchEvent(cancel);
+ cancel.recycle();
+ if (mExtension.getHeight() > 0) {
+ MotionEvent translated = MotionEvent.obtain(me.getEventTime(),
+ me.getEventTime(),
+ MotionEvent.ACTION_DOWN,
+ me.getX(), me.getY() + mExtension.getHeight(),
+ me.getMetaState());
+ mExtension.onTouchEvent(translated);
+ translated.recycle();
+ } else {
+ mFirstEvent = true;
+ }
+ }
+ return true;
+ }
+ } else if (mExtensionVisible) {
+ closeExtension();
+ // Send a down event into the main keyboard first
+ MotionEvent down = MotionEvent.obtain(me.getEventTime(), me.getEventTime(),
+ MotionEvent.ACTION_DOWN,
+ me.getX(), me.getY(), me.getMetaState());
+ super.onTouchEvent(down);
+ down.recycle();
+ // Send the actual event
+ return super.onTouchEvent(me);
+ } else {
+ return super.onTouchEvent(me);
+ }
+ }
+
+ private boolean openExtension() {
+ if (((LatinKeyboard) getKeyboard()).getExtension() == 0) return false;
+ makePopupWindow();
+ mExtensionVisible = true;
+ return true;
+ }
+
+ private void makePopupWindow() {
+ if (mExtensionPopup == null) {
+ int[] windowLocation = new int[2];
+ mExtensionPopup = new PopupWindow(getContext());
+ mExtensionPopup.setBackgroundDrawable(null);
+ LayoutInflater li = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mExtension = (LatinKeyboardView) li.inflate(R.layout.input, null);
+ mExtension.setOnKeyboardActionListener((LatinIME) getContext());
+ mExtension.setPopupParent(this);
+ mExtension.setPopupOffset(0, -windowLocation[1]);
+ Keyboard keyboard;
+ mExtension.setKeyboard(keyboard = new LatinKeyboard(getContext(),
+ ((LatinKeyboard) getKeyboard()).getExtension()));
+ mExtensionPopup.setContentView(mExtension);
+ mExtensionPopup.setWidth(getWidth());
+ mExtensionPopup.setHeight(keyboard.getHeight());
+ getLocationInWindow(windowLocation);
+ // TODO: Fix the "- 30".
+ mExtension.setPopupOffset(0, -windowLocation[1] - 30);
+ mExtensionPopup.showAtLocation(this, 0, 0, -keyboard.getHeight()
+ + windowLocation[1]);
+ } else {
+ mExtension.setVisibility(VISIBLE);
+ }
+ }
+
+ @Override
+ public void closing() {
+ super.closing();
+ if (mExtensionPopup != null && mExtensionPopup.isShowing()) {
+ mExtensionPopup.dismiss();
+ mExtensionPopup = null;
+ }
+ }
+
+ private void closeExtension() {
+ mExtension.setVisibility(INVISIBLE);
+ mExtension.closing();
+ mExtensionVisible = false;
+ }
+
/**************************** INSTRUMENTATION *******************************/
static final boolean DEBUG_AUTO_PLAY = false;
diff --git a/src/com/android/inputmethod/latin/Suggest.java b/src/com/android/inputmethod/latin/Suggest.java
index c025566b7..c3fe99635 100755
--- a/src/com/android/inputmethod/latin/Suggest.java
+++ b/src/com/android/inputmethod/latin/Suggest.java
@@ -26,6 +26,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import com.android.inputmethod.latin.WordComposer;
+
/**
* This class loads a dictionary and provides a list of suggestions for a given sequence of
* characters. This includes corrections and completions.
@@ -37,7 +39,9 @@ public class Suggest implements Dictionary.WordCallback {
public static final int CORRECTION_BASIC = 1;
public static final int CORRECTION_FULL = 2;
- private Dictionary mMainDict;
+ private static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
+
+ private BinaryDictionary mMainDict;
private Dictionary mUserDictionary;
@@ -49,18 +53,16 @@ public class Suggest implements Dictionary.WordCallback {
private int[] mPriorities = new int[mPrefMaxSuggestions];
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
- private boolean mIncludeTypedWordIfValid;
private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
- private Context mContext;
private boolean mHaveCorrection;
private CharSequence mOriginalWord;
private String mLowerOriginalWord;
+ private boolean mCapitalize;
private int mCorrectionMode = CORRECTION_BASIC;
public Suggest(Context context, int dictionaryResId) {
- mContext = context;
mMainDict = new BinaryDictionary(context, dictionaryResId);
for (int i = 0; i < mPrefMaxSuggestions; i++) {
StringBuilder sb = new StringBuilder(32);
@@ -76,6 +78,10 @@ public class Suggest implements Dictionary.WordCallback {
mCorrectionMode = mode;
}
+ public boolean hasMainDictionary() {
+ return mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
+ }
+
/**
* Sets an optional user dictionary resource to be loaded. The user dictionary is consulted
* before the main dictionary, if set.
@@ -153,9 +159,9 @@ public class Suggest implements Dictionary.WordCallback {
public List<CharSequence> getSuggestions(View view, WordComposer wordComposer,
boolean includeTypedWordIfValid) {
mHaveCorrection = false;
+ mCapitalize = wordComposer.isCapitalized();
collectGarbage();
Arrays.fill(mPriorities, 0);
- mIncludeTypedWordIfValid = includeTypedWordIfValid;
// Save a lowercase version of the original word
mOriginalWord = wordComposer.getTypedWord();
@@ -298,7 +304,14 @@ public class Suggest implements Dictionary.WordCallback {
StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
: new StringBuilder(32);
sb.setLength(0);
- sb.append(word, offset, length);
+ if (mCapitalize) {
+ sb.append(Character.toUpperCase(word[offset]));
+ if (length > 1) {
+ sb.append(word, offset + 1, length - 1);
+ }
+ } else {
+ sb.append(word, offset, length);
+ }
mSuggestions.add(pos, sb);
if (mSuggestions.size() > prefMaxSuggestions) {
CharSequence garbage = mSuggestions.remove(prefMaxSuggestions);
@@ -336,4 +349,10 @@ public class Suggest implements Dictionary.WordCallback {
}
mSuggestions.clear();
}
+
+ public void close() {
+ if (mMainDict != null) {
+ mMainDict.close();
+ }
+ }
}
diff --git a/src/com/android/inputmethod/latin/TextEntryState.java b/src/com/android/inputmethod/latin/TextEntryState.java
index 90c364a1c..c5e8ad9a1 100644
--- a/src/com/android/inputmethod/latin/TextEntryState.java
+++ b/src/com/android/inputmethod/latin/TextEntryState.java
@@ -123,6 +123,7 @@ public class TextEntryState {
}
public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord) {
+ if (typedWord == null) return;
if (!typedWord.equals(actualWord)) {
sAutoSuggestCount++;
}
diff --git a/src/com/android/inputmethod/latin/WordComposer.java b/src/com/android/inputmethod/latin/WordComposer.java
index 50725d481..e97cb24ba 100644
--- a/src/com/android/inputmethod/latin/WordComposer.java
+++ b/src/com/android/inputmethod/latin/WordComposer.java
@@ -36,6 +36,8 @@ public class WordComposer {
private StringBuilder mTypedWord;
private int mCapsCount;
+
+ private boolean mAutoCapitalized;
/**
* Whether the user chose to capitalize the word.
@@ -152,4 +154,21 @@ public class WordComposer {
public boolean isMostlyCaps() {
return mCapsCount > 1;
}
+
+ /**
+ * Saves the reason why the word is capitalized - whether it was automatic or
+ * due to the user hitting shift in the middle of a sentence.
+ * @param auto whether it was an automatic capitalization due to start of sentence
+ */
+ public void setAutoCapitalized(boolean auto) {
+ mAutoCapitalized = auto;
+ }
+
+ /**
+ * Returns whether the word was automatically capitalized.
+ * @return whether the word was automatically capitalized
+ */
+ public boolean isAutoCapitalized() {
+ return mAutoCapitalized;
+ }
}
diff --git a/src/com/android/inputmethod/voice/EditingUtil.java b/src/com/android/inputmethod/voice/EditingUtil.java
new file mode 100644
index 000000000..6316d8ccf
--- /dev/null
+++ b/src/com/android/inputmethod/voice/EditingUtil.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * Utility methods to deal with editing text through an InputConnection.
+ */
+public class EditingUtil {
+ private EditingUtil() {};
+
+ /**
+ * Append newText to the text field represented by connection.
+ * The new text becomes selected.
+ */
+ public static void appendText(InputConnection connection, String newText) {
+ if (connection == null) {
+ return;
+ }
+
+ // Commit the composing text
+ connection.finishComposingText();
+
+ // Add a space if the field already has text.
+ CharSequence charBeforeCursor = connection.getTextBeforeCursor(1, 0);
+ if (charBeforeCursor != null
+ && !charBeforeCursor.equals(" ")
+ && (charBeforeCursor.length() > 0)) {
+ newText = " " + newText;
+ }
+
+ connection.setComposingText(newText, 1);
+ }
+
+ private static int getCursorPosition(InputConnection connection) {
+ ExtractedText extracted = connection.getExtractedText(
+ new ExtractedTextRequest(), 0);
+ if (extracted == null) {
+ return -1;
+ }
+ return extracted.startOffset + extracted.selectionStart;
+ }
+
+ private static int getSelectionEnd(InputConnection connection) {
+ ExtractedText extracted = connection.getExtractedText(
+ new ExtractedTextRequest(), 0);
+ if (extracted == null) {
+ return -1;
+ }
+ return extracted.startOffset + extracted.selectionEnd;
+ }
+
+ /**
+ * @param connection connection to the current text field.
+ * @param sep characters which may separate words
+ * @return the word that surrounds the cursor, including up to one trailing
+ * separator. For example, if the field contains "he|llo world", where |
+ * represents the cursor, then "hello " will be returned.
+ */
+ public static String getWordAtCursor(
+ InputConnection connection, String separators) {
+ Range range = getWordRangeAtCursor(connection, separators);
+ return (range == null) ? null : range.word;
+ }
+
+ /**
+ * Removes the word surrounding the cursor. Parameters are identical to
+ * getWordAtCursor.
+ */
+ public static void deleteWordAtCursor(
+ InputConnection connection, String separators) {
+
+ Range range = getWordRangeAtCursor(connection, separators);
+ if (range == null) return;
+
+ connection.finishComposingText();
+ // Move cursor to beginning of word, to avoid crash when cursor is outside
+ // of valid range after deleting text.
+ int newCursor = getCursorPosition(connection) - range.charsBefore;
+ connection.setSelection(newCursor, newCursor);
+ connection.deleteSurroundingText(0, range.charsBefore + range.charsAfter);
+ }
+
+ /**
+ * Represents a range of text, relative to the current cursor position.
+ */
+ private static class Range {
+ /** Characters before selection start */
+ int charsBefore;
+
+ /**
+ * Characters after selection start, including one trailing word
+ * separator.
+ */
+ int charsAfter;
+
+ /** The actual characters that make up a word */
+ String word;
+
+ public Range(int charsBefore, int charsAfter, String word) {
+ if (charsBefore < 0 || charsAfter < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ this.charsBefore = charsBefore;
+ this.charsAfter = charsAfter;
+ this.word = word;
+ }
+ }
+
+ private static Range getWordRangeAtCursor(
+ InputConnection connection, String sep) {
+ if (connection == null || sep == null) {
+ return null;
+ }
+ CharSequence before = connection.getTextBeforeCursor(1000, 0);
+ CharSequence after = connection.getTextAfterCursor(1000, 0);
+ if (before == null || after == null) {
+ return null;
+ }
+
+ // Find first word separator before the cursor
+ int start = before.length();
+ while (--start > 0 && !isWhitespace(before.charAt(start - 1), sep));
+
+ // Find last word separator after the cursor
+ int end = -1;
+ while (++end < after.length() && !isWhitespace(after.charAt(end), sep));
+ if (end < after.length() - 1) {
+ end++; // Include trailing space, if it exists, in word
+ }
+
+ int cursor = getCursorPosition(connection);
+ if (start >= 0 && cursor + end <= after.length() + before.length()) {
+ String word = before.toString().substring(start, before.length())
+ + after.toString().substring(0, end);
+ return new Range(before.length() - start, end, word);
+ }
+
+ return null;
+ }
+
+ private static boolean isWhitespace(int code, String whitespace) {
+ return whitespace.contains(String.valueOf((char) code));
+ }
+}
diff --git a/src/com/android/inputmethod/voice/FieldContext.java b/src/com/android/inputmethod/voice/FieldContext.java
new file mode 100644
index 000000000..5fbacfb6c
--- /dev/null
+++ b/src/com/android/inputmethod/voice/FieldContext.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * Represents information about a given text field, which can be passed
+ * to the speech recognizer as context information.
+ */
+public class FieldContext {
+ private static final boolean DBG = false;
+
+ static final String LABEL = "label";
+ static final String HINT = "hint";
+ static final String PACKAGE_NAME = "packageName";
+ static final String FIELD_ID = "fieldId";
+ static final String FIELD_NAME = "fieldName";
+ static final String SINGLE_LINE = "singleLine";
+ static final String INPUT_TYPE = "inputType";
+ static final String IME_OPTIONS = "imeOptions";
+ static final String SELECTED_LANGUAGE = "selectedLanguage";
+ static final String ENABLED_LANGUAGES = "enabledLanguages";
+
+ Bundle mFieldInfo;
+
+ public FieldContext(InputConnection conn, EditorInfo info,
+ String selectedLanguage, String[] enabledLanguages) {
+ mFieldInfo = new Bundle();
+ addEditorInfoToBundle(info, mFieldInfo);
+ addInputConnectionToBundle(conn, mFieldInfo);
+ addLanguageInfoToBundle(selectedLanguage, enabledLanguages, mFieldInfo);
+ if (DBG) Log.i("FieldContext", "Bundle = " + mFieldInfo.toString());
+ }
+
+ private static String safeToString(Object o) {
+ if (o == null) {
+ return "";
+ }
+ return o.toString();
+ }
+
+ private static void addEditorInfoToBundle(EditorInfo info, Bundle bundle) {
+ if (info == null) {
+ return;
+ }
+
+ bundle.putString(LABEL, safeToString(info.label));
+ bundle.putString(HINT, safeToString(info.hintText));
+ bundle.putString(PACKAGE_NAME, safeToString(info.packageName));
+ bundle.putInt(FIELD_ID, info.fieldId);
+ bundle.putString(FIELD_NAME, safeToString(info.fieldName));
+ bundle.putInt(INPUT_TYPE, info.inputType);
+ bundle.putInt(IME_OPTIONS, info.imeOptions);
+ }
+
+ private static void addInputConnectionToBundle(
+ InputConnection conn, Bundle bundle) {
+ if (conn == null) {
+ return;
+ }
+
+ ExtractedText et = conn.getExtractedText(new ExtractedTextRequest(), 0);
+ if (et == null) {
+ return;
+ }
+ bundle.putBoolean(SINGLE_LINE, (et.flags & et.FLAG_SINGLE_LINE) > 0);
+ }
+
+ private static void addLanguageInfoToBundle(
+ String selectedLanguage, String[] enabledLanguages, Bundle bundle) {
+ bundle.putString(SELECTED_LANGUAGE, selectedLanguage);
+ bundle.putStringArray(ENABLED_LANGUAGES, enabledLanguages);
+ }
+
+ public Bundle getBundle() {
+ return mFieldInfo;
+ }
+
+ public String toString() {
+ return mFieldInfo.toString();
+ }
+}
diff --git a/src/com/android/inputmethod/voice/LatinIMEWithVoice.java b/src/com/android/inputmethod/voice/LatinIMEWithVoice.java
new file mode 100644
index 000000000..ccbf5b6bc
--- /dev/null
+++ b/src/com/android/inputmethod/voice/LatinIMEWithVoice.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import android.content.Intent;
+
+import com.android.inputmethod.latin.LatinIME;
+
+public class LatinIMEWithVoice extends LatinIME {
+ @Override
+ protected void launchSettings() {
+ launchSettings(LatinIMEWithVoiceSettings.class);
+ }
+}
diff --git a/src/com/android/inputmethod/voice/LatinIMEWithVoiceSettings.java b/src/com/android/inputmethod/voice/LatinIMEWithVoiceSettings.java
new file mode 100644
index 000000000..13a58e14d
--- /dev/null
+++ b/src/com/android/inputmethod/voice/LatinIMEWithVoiceSettings.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import com.android.inputmethod.latin.LatinIMESettings;
+
+public class LatinIMEWithVoiceSettings extends LatinIMESettings {}
diff --git a/src/com/android/inputmethod/voice/RecognitionView.java b/src/com/android/inputmethod/voice/RecognitionView.java
new file mode 100644
index 000000000..fd3d6d0de
--- /dev/null
+++ b/src/com/android/inputmethod/voice/RecognitionView.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.CornerPathEffect;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathEffect;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.voice.SettingsUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The user interface for the "Speak now" and "working" states.
+ * Displays a recognition dialog (with waveform, voice meter, etc.),
+ * plays beeps, shows errors, etc.
+ */
+public class RecognitionView {
+ private static final String TAG = "RecognitionView";
+
+ // If there's a significant delay between starting up voice search and the
+ // onset of audio recording, show the "initializing" screen first. If not,
+ // jump directly to the "speak now" screen to avoid flashing "initializing"
+ // quickly.
+ private static final boolean EXPECT_RECORDING_DELAY = true;
+
+ private Handler mUiHandler; // Reference to UI thread
+ private View mView;
+ private Context mContext;
+
+ private ImageView mImage;
+ private TextView mText;
+ private View mButton;
+ private TextView mButtonText;
+ private View mProgress;
+
+ private Drawable mInitializing;
+ private Drawable mError;
+ private List<Drawable> mSpeakNow;
+
+ private float mVolume = 0.0f;
+ private int mLevel = 0;
+
+ private enum State {LISTENING, WORKING, READY}
+ private State mState = State.READY;
+
+ private float mMinMicrophoneLevel;
+ private float mMaxMicrophoneLevel;
+
+ /** Updates the microphone icon to show user their volume.*/
+ private Runnable mUpdateVolumeRunnable = new Runnable() {
+ public void run() {
+ if (mState != State.LISTENING) {
+ return;
+ }
+
+ final float min = mMinMicrophoneLevel;
+ final float max = mMaxMicrophoneLevel;
+ final int maxLevel = mSpeakNow.size() - 1;
+
+ int index = (int) ((mVolume - min) / (max - min) * maxLevel);
+ final int level = Math.min(Math.max(0, index), maxLevel);
+
+ if (level != mLevel) {
+ mImage.setImageDrawable(mSpeakNow.get(level));
+ mLevel = level;
+ }
+ mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
+ }
+ };
+
+ public RecognitionView(Context context, OnClickListener clickListener) {
+ mUiHandler = new Handler();
+
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mView = inflater.inflate(R.layout.recognition_status, null);
+
+ ContentResolver cr = context.getContentResolver();
+ mMinMicrophoneLevel = SettingsUtil.getSettingsFloat(
+ cr, SettingsUtil.LATIN_IME_MIN_MICROPHONE_LEVEL, 15.f);
+ mMaxMicrophoneLevel = SettingsUtil.getSettingsFloat(
+ cr, SettingsUtil.LATIN_IME_MAX_MICROPHONE_LEVEL, 30.f);
+
+ // Pre-load volume level images
+ Resources r = context.getResources();
+
+ mSpeakNow = new ArrayList<Drawable>();
+ mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level0));
+ mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level1));
+ mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level2));
+ mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level3));
+ mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level4));
+ mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level5));
+ mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level6));
+
+ mInitializing = r.getDrawable(R.drawable.mic_slash);
+ mError = r.getDrawable(R.drawable.caution);
+
+ mImage = (ImageView) mView.findViewById(R.id.image);
+ mButton = mView.findViewById(R.id.button);
+ mButton.setOnClickListener(clickListener);
+ mText = (TextView) mView.findViewById(R.id.text);
+ mButtonText = (TextView) mView.findViewById(R.id.button_text);
+ mProgress = mView.findViewById(R.id.progress);
+
+ mContext = context;
+ }
+
+ public View getView() {
+ return mView;
+ }
+
+ public void showInitializing() {
+ mUiHandler.post(new Runnable() {
+ public void run() {
+ mText.setText(R.string.voice_initializing);
+ mImage.setImageDrawable(mInitializing);
+ mButtonText.setText(mContext.getText(R.string.cancel));
+ }
+ });
+ }
+
+ public void showStartState() {
+ if (EXPECT_RECORDING_DELAY) {
+ showInitializing();
+ } else {
+ showListening();
+ }
+ }
+
+ public void showListening() {
+ mState = State.LISTENING;
+ mUiHandler.post(new Runnable() {
+ public void run() {
+ mText.setText(R.string.voice_listening);
+ mImage.setImageDrawable(mSpeakNow.get(0));
+ mButtonText.setText(mContext.getText(R.string.cancel));
+ }
+ });
+ mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
+ }
+
+ public void updateVoiceMeter(final float rmsdB) {
+ mVolume = rmsdB;
+ }
+
+ public void showError(final String message) {
+ mState = State.READY;
+ mUiHandler.post(new Runnable() {
+ public void run() {
+ exitWorking();
+ mText.setText(message);
+ mImage.setImageDrawable(mError);
+ mButtonText.setText(mContext.getText(R.string.ok));
+ }
+ });
+ }
+
+ public void showWorking(
+ final ByteArrayOutputStream waveBuffer,
+ final int speechStartPosition,
+ final int speechEndPosition) {
+
+ mState = State.WORKING;
+
+ mUiHandler.post(new Runnable() {
+ public void run() {
+ mText.setText(R.string.voice_working);
+ mImage.setVisibility(View.GONE);
+ mProgress.setVisibility(View.VISIBLE);
+ final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray())
+ .order(ByteOrder.nativeOrder()).asShortBuffer();
+ buf.position(0);
+ waveBuffer.reset();
+ showWave(buf, speechStartPosition / 2, speechEndPosition / 2);
+ }
+ });
+ }
+
+ /**
+ * @return an average abs of the specified buffer.
+ */
+ private static int getAverageAbs(ShortBuffer buffer, int start, int i, int npw) {
+ int from = start + i * npw;
+ int end = from + npw;
+ int total = 0;
+ for (int x = from; x < end; x++) {
+ total += Math.abs(buffer.get(x));
+ }
+ return total / npw;
+ }
+
+
+ /**
+ * Shows waveform of input audio.
+ *
+ * Copied from version in VoiceSearch's RecognitionActivity.
+ *
+ * TODO: adjust stroke width based on the size of data.
+ * TODO: use dip rather than pixels.
+ */
+ private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) {
+ final int w = ((View) mImage.getParent()).getWidth();
+ final int h = mImage.getHeight();
+ if (w <= 0 || h <= 0) {
+ // view is not visible this time. Skip drawing.
+ return;
+ }
+ final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ final Canvas c = new Canvas(b);
+ final Paint paint = new Paint();
+ paint.setColor(0xFFFFFFFF); // 0xAARRGGBB
+ paint.setAntiAlias(true);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setAlpha(0x90);
+
+ final PathEffect effect = new CornerPathEffect(3);
+ paint.setPathEffect(effect);
+
+ final int numSamples = waveBuffer.remaining();
+ int endIndex;
+ if (endPosition == 0) {
+ endIndex = numSamples;
+ } else {
+ endIndex = Math.min(endPosition, numSamples);
+ }
+
+ int startIndex = startPosition - 2000; // include 250ms before speech
+ if (startIndex < 0) {
+ startIndex = 0;
+ }
+ final int numSamplePerWave = 200; // 8KHz 25ms = 200 samples
+ final float scale = 10.0f / 65536.0f;
+
+ final int count = (endIndex - startIndex) / numSamplePerWave;
+ final float deltaX = 1.0f * w / count;
+ int yMax = h / 2 - 10;
+ Path path = new Path();
+ c.translate(0, yMax);
+ float x = 0;
+ path.moveTo(x, 0);
+ yMax -= 10;
+ for (int i = 0; i < count; i++) {
+ final int avabs = getAverageAbs(waveBuffer, startIndex, i , numSamplePerWave);
+ int sign = ( (i & 01) == 0) ? -1 : 1;
+ final float y = Math.min(yMax, avabs * h * scale) * sign;
+ path.lineTo(x, y);
+ x += deltaX;
+ path.lineTo(x, y);
+ }
+ if (deltaX > 4) {
+ paint.setStrokeWidth(3);
+ } else {
+ paint.setStrokeWidth(Math.max(1, (int) (deltaX -.05)));
+ }
+ c.drawPath(path, paint);
+ mImage.setImageBitmap(b);
+ mImage.setVisibility(View.VISIBLE);
+ MarginLayoutParams mProgressParams = (MarginLayoutParams)mProgress.getLayoutParams();
+ mProgressParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ -h / 2 - 18, mContext.getResources().getDisplayMetrics());
+
+ // Tweak the padding manually to fill out the whole view horizontally.
+ // TODO: Do this in the xml layout instead.
+ ((View) mImage.getParent()).setPadding(4, ((View) mImage.getParent()).getPaddingTop(), 3,
+ ((View) mImage.getParent()).getPaddingBottom());
+ mProgress.setLayoutParams(mProgressParams);
+ }
+
+
+ public void finish() {
+ mState = State.READY;
+ mUiHandler.post(new Runnable() {
+ public void run() {
+ exitWorking();
+ }
+ });
+ showStartState();
+ }
+
+ private void exitWorking() {
+ mProgress.setVisibility(View.GONE);
+ mImage.setVisibility(View.VISIBLE);
+ }
+}
diff --git a/src/com/android/inputmethod/voice/SettingsUtil.java b/src/com/android/inputmethod/voice/SettingsUtil.java
new file mode 100644
index 000000000..abf52047f
--- /dev/null
+++ b/src/com/android/inputmethod/voice/SettingsUtil.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.Settings;
+import android.util.Log;
+
+/**
+ * Utility for retrieving settings from Settings.Secure.
+ */
+public class SettingsUtil {
+ /**
+ * A whitespace-separated list of supported locales for voice input from the keyboard.
+ */
+ public static final String LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES =
+ "latin_ime_voice_input_supported_locales";
+
+ /**
+ * A whitespace-separated list of recommended app packages for voice input from the
+ * keyboard.
+ */
+ public static final String LATIN_IME_VOICE_INPUT_RECOMMENDED_PACKAGES =
+ "latin_ime_voice_input_recommended_packages";
+
+ /**
+ * The maximum number of unique days to show the swipe hint for voice input.
+ */
+ public static final String LATIN_IME_VOICE_INPUT_SWIPE_HINT_MAX_DAYS =
+ "latin_ime_voice_input_swipe_hint_max_days";
+
+ /**
+ * The maximum number of times to show the punctuation hint for voice input.
+ */
+ public static final String LATIN_IME_VOICE_INPUT_PUNCTUATION_HINT_MAX_DISPLAYS =
+ "latin_ime_voice_input_punctuation_hint_max_displays";
+
+ /**
+ * Endpointer parameters for voice input from the keyboard.
+ */
+ public static final String LATIN_IME_SPEECH_MINIMUM_LENGTH_MILLIS =
+ "latin_ime_speech_minimum_length_millis";
+ public static final String LATIN_IME_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS =
+ "latin_ime_speech_input_complete_silence_length_millis";
+ public static final String LATIN_IME_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS =
+ "latin_ime_speech_input_possibly_complete_silence_length_millis";
+
+ /**
+ * Min and max volume levels that can be displayed on the "speak now" screen.
+ */
+ public static final String LATIN_IME_MIN_MICROPHONE_LEVEL =
+ "latin_ime_min_microphone_level";
+ public static final String LATIN_IME_MAX_MICROPHONE_LEVEL =
+ "latin_ime_max_microphone_level";
+
+ /**
+ * The number of sentence-level alternates to request of the server.
+ */
+ public static final String LATIN_IME_MAX_VOICE_RESULTS = "latin_ime_max_voice_results";
+
+ /**
+ * Get a string-valued setting.
+ *
+ * @param cr The content resolver to use
+ * @param key The setting to look up
+ * @param defaultValue The default value to use if none can be found
+ * @return The value of the setting, or defaultValue if it couldn't be found
+ */
+ public static String getSettingsString(ContentResolver cr, String key, String defaultValue) {
+ String result = Settings.Secure.getString(cr, key);
+ return (result == null) ? defaultValue : result;
+ }
+
+ /**
+ * Get an int-valued setting.
+ *
+ * @param cr The content resolver to use
+ * @param key The setting to look up
+ * @param defaultValue The default value to use if the setting couldn't be found or parsed
+ * @return The value of the setting, or defaultValue if it couldn't be found or parsed
+ */
+ public static int getSettingsInt(ContentResolver cr, String key, int defaultValue) {
+ return Settings.Secure.getInt(cr, key, defaultValue);
+ }
+
+ /**
+ * Get a float-valued setting.
+ *
+ * @param cr The content resolver to use
+ * @param key The setting to look up
+ * @param defaultValue The default value to use if the setting couldn't be found or parsed
+ * @return The value of the setting, or defaultValue if it couldn't be found or parsed
+ */
+ public static float getSettingsFloat(ContentResolver cr, String key, float defaultValue) {
+ return Settings.Secure.getFloat(cr, key, defaultValue);
+ }
+}
diff --git a/src/com/android/inputmethod/voice/VoiceInput.java b/src/com/android/inputmethod/voice/VoiceInput.java
new file mode 100644
index 000000000..a2e210536
--- /dev/null
+++ b/src/com/android/inputmethod/voice/VoiceInput.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import com.android.inputmethod.latin.R;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.speech.RecognitionListener;
+import android.speech.RecognitionManager;
+import android.speech.RecognizerIntent;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Speech recognition input, including both user interface and a background
+ * process to stream audio to the network recognizer. This class supplies a
+ * View (getView()), which it updates as recognition occurs. The user of this
+ * class is responsible for making the view visible to the user, as well as
+ * handling various events returned through UiListener.
+ */
+public class VoiceInput implements OnClickListener {
+ private static final String TAG = "VoiceInput";
+ private static final String EXTRA_RECOGNITION_CONTEXT =
+ "android.speech.extras.RECOGNITION_CONTEXT";
+ private static final String EXTRA_CALLING_PACKAGE = "calling_package";
+
+ private static final String DEFAULT_RECOMMENDED_PACKAGES =
+ "com.android.mms " +
+ "com.google.android.gm " +
+ "com.google.android.talk " +
+ "com.google.android.apps.googlevoice " +
+ "com.android.email " +
+ "com.android.browser ";
+
+ // WARNING! Before enabling this, fix the problem with calling getExtractedText() in
+ // landscape view. It causes Extracted text updates to be rejected due to a token mismatch
+ public static boolean ENABLE_WORD_CORRECTIONS = false;
+
+ // Dummy word suggestion which means "delete current word"
+ public static final String DELETE_SYMBOL = " \u00D7 "; // times symbol
+
+ private Whitelist mRecommendedList;
+ private Whitelist mBlacklist;
+
+ private VoiceInputLogger mLogger;
+
+ // Names of a few intent extras defined in VoiceSearch's RecognitionService.
+ // These let us tweak the endpointer parameters.
+ private static final String EXTRA_SPEECH_MINIMUM_LENGTH_MILLIS =
+ "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS";
+ private static final String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS =
+ "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS";
+ private static final String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS =
+ "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS";
+
+ // The usual endpointer default value for input complete silence length is 0.5 seconds,
+ // but that's used for things like voice search. For dictation-like voice input like this,
+ // we go with a more liberal value of 1 second. This value will only be used if a value
+ // is not provided from Gservices.
+ private static final String INPUT_COMPLETE_SILENCE_LENGTH_DEFAULT_VALUE_MILLIS = "1000";
+
+ // Used to record part of that state for logging purposes.
+ public static final int DEFAULT = 0;
+ public static final int LISTENING = 1;
+ public static final int WORKING = 2;
+ public static final int ERROR = 3;
+
+ private int mState = DEFAULT;
+
+ private final static int MSG_CLOSE_ERROR_DIALOG = 1;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_CLOSE_ERROR_DIALOG) {
+ mState = DEFAULT;
+ mRecognitionView.finish();
+ mUiListener.onCancelVoice();
+ }
+ }
+ };
+
+ /**
+ * Events relating to the recognition UI. You must implement these.
+ */
+ public interface UiListener {
+
+ /**
+ * @param recognitionResults a set of transcripts for what the user
+ * spoke, sorted by likelihood.
+ */
+ public void onVoiceResults(
+ List<String> recognitionResults,
+ Map<String, List<CharSequence>> alternatives);
+
+ /**
+ * Called when the user cancels speech recognition.
+ */
+ public void onCancelVoice();
+ }
+
+ private RecognitionManager mRecognitionManager;
+ private RecognitionListener mRecognitionListener;
+ private RecognitionView mRecognitionView;
+ private UiListener mUiListener;
+ private Context mContext;
+
+ /**
+ * @param context the service or activity in which we're running.
+ * @param uiHandler object to receive events from VoiceInput.
+ */
+ public VoiceInput(Context context, UiListener uiHandler) {
+ mLogger = VoiceInputLogger.getLogger(context);
+ mRecognitionListener = new ImeRecognitionListener();
+ mRecognitionManager = RecognitionManager.createRecognitionManager(context);
+ mRecognitionManager.setRecognitionListener(mRecognitionListener);
+ mUiListener = uiHandler;
+ mContext = context;
+ newView();
+
+ String recommendedPackages = SettingsUtil.getSettingsString(
+ context.getContentResolver(),
+ SettingsUtil.LATIN_IME_VOICE_INPUT_RECOMMENDED_PACKAGES,
+ DEFAULT_RECOMMENDED_PACKAGES);
+
+ mRecommendedList = new Whitelist();
+ for (String recommendedPackage : recommendedPackages.split("\\s+")) {
+ mRecommendedList.addApp(recommendedPackage);
+ }
+
+ mBlacklist = new Whitelist();
+ mBlacklist.addApp("com.android.setupwizard");
+ }
+
+ /**
+ * @return true if field is blacklisted for voice
+ */
+ public boolean isBlacklistedField(FieldContext context) {
+ return mBlacklist.matches(context);
+ }
+
+ /**
+ * Used to decide whether to show voice input hints for this field, etc.
+ *
+ * @return true if field is recommended for voice
+ */
+ public boolean isRecommendedField(FieldContext context) {
+ return mRecommendedList.matches(context);
+ }
+
+ /**
+ * Start listening for speech from the user. This will grab the microphone
+ * and start updating the view provided by getView(). It is the caller's
+ * responsibility to ensure that the view is visible to the user at this stage.
+ *
+ * @param context the same FieldContext supplied to voiceIsEnabled()
+ * @param swipe whether this voice input was started by swipe, for logging purposes
+ */
+ public void startListening(FieldContext context, boolean swipe) {
+ mState = DEFAULT;
+
+ Locale locale = Locale.getDefault();
+ String localeString = locale.getLanguage() + "-" + locale.getCountry();
+
+ mLogger.start(localeString, swipe);
+
+ mState = LISTENING;
+
+ mRecognitionView.showInitializing();
+ startListeningAfterInitialization(context);
+ }
+
+ /**
+ * Called only when the recognition manager's initialization completed
+ *
+ * @param context context with which {@link #startListening(FieldContext, boolean)} was executed
+ */
+ private void startListeningAfterInitialization(FieldContext context) {
+ Intent intent = makeIntent();
+ intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "");
+ intent.putExtra(EXTRA_RECOGNITION_CONTEXT, context.getBundle());
+ intent.putExtra(EXTRA_CALLING_PACKAGE, "VoiceIME");
+ intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS,
+ SettingsUtil.getSettingsInt(
+ mContext.getContentResolver(),
+ SettingsUtil.LATIN_IME_MAX_VOICE_RESULTS,
+ 1));
+
+ // Get endpointer params from Gservices.
+ // TODO: Consider caching these values for improved performance on slower devices.
+ final ContentResolver cr = mContext.getContentResolver();
+ putEndpointerExtra(
+ cr,
+ intent,
+ SettingsUtil.LATIN_IME_SPEECH_MINIMUM_LENGTH_MILLIS,
+ EXTRA_SPEECH_MINIMUM_LENGTH_MILLIS,
+ null /* rely on endpointer default */);
+ putEndpointerExtra(
+ cr,
+ intent,
+ SettingsUtil.LATIN_IME_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
+ EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
+ INPUT_COMPLETE_SILENCE_LENGTH_DEFAULT_VALUE_MILLIS
+ /* our default value is different from the endpointer's */);
+ putEndpointerExtra(
+ cr,
+ intent,
+ SettingsUtil.
+ LATIN_IME_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
+ EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
+ null /* rely on endpointer default */);
+
+ mRecognitionManager.startListening(intent);
+ }
+
+ /**
+ * Gets the value of the provided Gservices key, attempts to parse it into a long,
+ * and if successful, puts the long value as an extra in the provided intent.
+ */
+ private void putEndpointerExtra(ContentResolver cr, Intent i,
+ String gservicesKey, String intentExtraKey, String defaultValue) {
+ long l = -1;
+ String s = SettingsUtil.getSettingsString(cr, gservicesKey, defaultValue);
+ if (s != null) {
+ try {
+ l = Long.valueOf(s);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not parse value for " + gservicesKey + ": " + s);
+ }
+ }
+
+ if (l != -1) i.putExtra(intentExtraKey, l);
+ }
+
+ public void destroy() {
+ mRecognitionManager.destroy();
+ }
+
+ /**
+ * Creates a new instance of the view that is returned by {@link #getView()}
+ * Clients should use this when a previously returned view is stuck in a
+ * layout that is being thrown away and a new one is need to show to the
+ * user.
+ */
+ public void newView() {
+ mRecognitionView = new RecognitionView(mContext, this);
+ }
+
+ /**
+ * @return a view that shows the recognition flow--e.g., "Speak now" and
+ * "working" dialogs.
+ */
+ public View getView() {
+ return mRecognitionView.getView();
+ }
+
+ /**
+ * Handle the cancel button.
+ */
+ public void onClick(View view) {
+ switch(view.getId()) {
+ case R.id.button:
+ cancel();
+ break;
+ }
+ }
+
+ public void logTextModified() {
+ mLogger.textModified();
+ }
+
+ public void logKeyboardWarningDialogShown() {
+ mLogger.keyboardWarningDialogShown();
+ }
+
+ public void logKeyboardWarningDialogDismissed() {
+ mLogger.keyboardWarningDialogDismissed();
+ }
+
+ public void logKeyboardWarningDialogOk() {
+ mLogger.keyboardWarningDialogOk();
+ }
+
+ public void logKeyboardWarningDialogCancel() {
+ mLogger.keyboardWarningDialogCancel();
+ }
+
+ public void logSwipeHintDisplayed() {
+ mLogger.swipeHintDisplayed();
+ }
+
+ public void logPunctuationHintDisplayed() {
+ mLogger.punctuationHintDisplayed();
+ }
+
+ public void logVoiceInputDelivered() {
+ mLogger.voiceInputDelivered();
+ }
+
+ public void logNBestChoose(int index) {
+ mLogger.nBestChoose(index);
+ }
+
+ public void logInputEnded() {
+ mLogger.inputEnded();
+ }
+
+ public void flushLogs() {
+ mLogger.flush();
+ }
+
+ private static Intent makeIntent() {
+ Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+
+ // On Cupcake, use VoiceIMEHelper since VoiceSearch doesn't support.
+ // On Donut, always use VoiceSearch, since VoiceIMEHelper and
+ // VoiceSearch may conflict.
+ if (Build.VERSION.RELEASE.equals("1.5")) {
+ intent = intent.setClassName(
+ "com.google.android.voiceservice",
+ "com.google.android.voiceservice.IMERecognitionService");
+ } else {
+ intent = intent.setClassName(
+ "com.google.android.voicesearch",
+ "com.google.android.voicesearch.RecognitionService");
+ }
+
+ return intent;
+ }
+
+ /**
+ * Cancel in-progress speech recognition.
+ */
+ public void cancel() {
+ switch (mState) {
+ case LISTENING:
+ mLogger.cancelDuringListening();
+ break;
+ case WORKING:
+ mLogger.cancelDuringWorking();
+ break;
+ case ERROR:
+ mLogger.cancelDuringError();
+ break;
+ }
+ mState = DEFAULT;
+
+ // Remove all pending tasks (e.g., timers to cancel voice input)
+ mHandler.removeMessages(MSG_CLOSE_ERROR_DIALOG);
+
+ mRecognitionManager.cancel();
+ mUiListener.onCancelVoice();
+ mRecognitionView.finish();
+ }
+
+ private int getErrorStringId(int errorType, boolean endpointed) {
+ switch (errorType) {
+ // We use CLIENT_ERROR to signify that voice search is not available on the device.
+ case RecognitionManager.ERROR_CLIENT:
+ return R.string.voice_not_installed;
+ case RecognitionManager.ERROR_NETWORK:
+ return R.string.voice_network_error;
+ case RecognitionManager.ERROR_NETWORK_TIMEOUT:
+ return endpointed ?
+ R.string.voice_network_error : R.string.voice_too_much_speech;
+ case RecognitionManager.ERROR_AUDIO:
+ return R.string.voice_audio_error;
+ case RecognitionManager.ERROR_SERVER:
+ return R.string.voice_server_error;
+ case RecognitionManager.ERROR_SPEECH_TIMEOUT:
+ return R.string.voice_speech_timeout;
+ case RecognitionManager.ERROR_NO_MATCH:
+ return R.string.voice_no_match;
+ default: return R.string.voice_error;
+ }
+ }
+
+ private void onError(int errorType, boolean endpointed) {
+ Log.i(TAG, "error " + errorType);
+ mLogger.error(errorType);
+ onError(mContext.getString(getErrorStringId(errorType, endpointed)));
+ }
+
+ private void onError(String error) {
+ mState = ERROR;
+ mRecognitionView.showError(error);
+ // Wait a couple seconds and then automatically dismiss message.
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_CLOSE_ERROR_DIALOG), 2000);
+ }
+
+ private class ImeRecognitionListener implements RecognitionListener {
+ // Waveform data
+ final ByteArrayOutputStream mWaveBuffer = new ByteArrayOutputStream();
+ int mSpeechStart;
+ private boolean mEndpointed = false;
+
+ public void onReadyForSpeech(Bundle noiseParams) {
+ mRecognitionView.showListening();
+ }
+
+ public void onBeginningOfSpeech() {
+ mEndpointed = false;
+ mSpeechStart = mWaveBuffer.size();
+ }
+
+ public void onRmsChanged(float rmsdB) {
+ mRecognitionView.updateVoiceMeter(rmsdB);
+ }
+
+ public void onBufferReceived(byte[] buf) {
+ try {
+ mWaveBuffer.write(buf);
+ } catch (IOException e) {}
+ }
+
+ public void onEndOfSpeech() {
+ mEndpointed = true;
+ mState = WORKING;
+ mRecognitionView.showWorking(mWaveBuffer, mSpeechStart, mWaveBuffer.size());
+ }
+
+ public void onError(int errorType) {
+ mState = ERROR;
+ VoiceInput.this.onError(errorType, mEndpointed);
+ }
+
+ public void onResults(Bundle resultsBundle) {
+ List<String> results = resultsBundle
+ .getStringArrayList(RecognitionManager.RESULTS_RECOGNITION);
+ mState = DEFAULT;
+
+ final Map<String, List<CharSequence>> alternatives =
+ new HashMap<String, List<CharSequence>>();
+ if (results.size() >= 2 && ENABLE_WORD_CORRECTIONS) {
+ final String[][] words = new String[results.size()][];
+ for (int i = 0; i < words.length; i++) {
+ words[i] = results.get(i).split(" ");
+ }
+
+ for (int key = 0; key < words[0].length; key++) {
+ alternatives.put(words[0][key], new ArrayList<CharSequence>());
+ for (int alt = 1; alt < words.length; alt++) {
+ int keyBegin = key * words[alt].length / words[0].length;
+ int keyEnd = (key + 1) * words[alt].length / words[0].length;
+
+ for (int i = keyBegin; i < Math.min(words[alt].length, keyEnd); i++) {
+ List<CharSequence> altList = alternatives.get(words[0][key]);
+ if (!altList.contains(words[alt][i]) && altList.size() < 6) {
+ altList.add(words[alt][i]);
+ }
+ }
+ }
+ }
+ }
+
+ if (results.size() > 5) {
+ results = results.subList(0, 5);
+ }
+ mUiListener.onVoiceResults(results, alternatives);
+ mRecognitionView.finish();
+ }
+
+ public void onPartialResults(final Bundle partialResults) {
+ // currently - do nothing
+ }
+
+ public void onEvent(int eventType, Bundle params) {
+ // do nothing - reserved for events that might be added in the future
+ }
+ }
+}
diff --git a/src/com/android/inputmethod/voice/VoiceInputLogger.java b/src/com/android/inputmethod/voice/VoiceInputLogger.java
new file mode 100644
index 000000000..659033340
--- /dev/null
+++ b/src/com/android/inputmethod/voice/VoiceInputLogger.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.voice;
+
+import com.android.common.speech.LoggingEvents;
+
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Provides the logging facility for voice input events. This fires broadcasts back to
+ * the voice search app which then logs on our behalf.
+ *
+ * Note that debug console logging does not occur in this class. If you want to
+ * see console output of these logging events, there is a boolean switch to turn
+ * on on the VoiceSearch side.
+ */
+public class VoiceInputLogger {
+ private static final String TAG = VoiceInputLogger.class.getSimpleName();
+
+ private static VoiceInputLogger sVoiceInputLogger;
+
+ private final Context mContext;
+
+ // The base intent used to form all broadcast intents to the logger
+ // in VoiceSearch.
+ private final Intent mBaseIntent;
+
+ /**
+ * Returns the singleton of the logger.
+ *
+ * @param contextHint a hint context used when creating the logger instance.
+ * Ignored if the singleton instance already exists.
+ */
+ public static synchronized VoiceInputLogger getLogger(Context contextHint) {
+ if (sVoiceInputLogger == null) {
+ sVoiceInputLogger = new VoiceInputLogger(contextHint);
+ }
+ return sVoiceInputLogger;
+ }
+
+ public VoiceInputLogger(Context context) {
+ mContext = context;
+
+ mBaseIntent = new Intent(LoggingEvents.ACTION_LOG_EVENT);
+ mBaseIntent.putExtra(LoggingEvents.EXTRA_APP_NAME, LoggingEvents.VoiceIme.APP_NAME);
+ }
+
+ private Intent newLoggingBroadcast(int event) {
+ Intent i = new Intent(mBaseIntent);
+ i.putExtra(LoggingEvents.EXTRA_EVENT, event);
+ return i;
+ }
+
+ public void flush() {
+ Intent i = new Intent(mBaseIntent);
+ i.putExtra(LoggingEvents.EXTRA_FLUSH, true);
+ mContext.sendBroadcast(i);
+ }
+
+ public void keyboardWarningDialogShown() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_SHOWN));
+ }
+
+ public void keyboardWarningDialogDismissed() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_DISMISSED));
+ }
+
+ public void keyboardWarningDialogOk() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_OK));
+ }
+
+ public void keyboardWarningDialogCancel() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_CANCEL));
+ }
+
+ public void settingsWarningDialogShown() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_SHOWN));
+ }
+
+ public void settingsWarningDialogDismissed() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_DISMISSED));
+ }
+
+ public void settingsWarningDialogOk() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_OK));
+ }
+
+ public void settingsWarningDialogCancel() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_CANCEL));
+ }
+
+ public void swipeHintDisplayed() {
+ mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.SWIPE_HINT_DISPLAYED));
+ }
+
+ public void cancelDuringListening() {
+ mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_LISTENING));
+ }
+
+ public void cancelDuringWorking() {
+ mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_WORKING));
+ }
+
+ public void cancelDuringError() {
+ mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_ERROR));
+ }
+
+ public void punctuationHintDisplayed() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.PUNCTUATION_HINT_DISPLAYED));
+ }
+
+ public void error(int code) {
+ Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.ERROR);
+ i.putExtra(LoggingEvents.VoiceIme.EXTRA_ERROR_CODE, code);
+ mContext.sendBroadcast(i);
+ }
+
+ public void start(String locale, boolean swipe) {
+ Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.START);
+ i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_LOCALE, locale);
+ i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_SWIPE, swipe);
+ i.putExtra(LoggingEvents.EXTRA_TIMESTAMP, System.currentTimeMillis());
+ mContext.sendBroadcast(i);
+ }
+
+ public void voiceInputDelivered() {
+ mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.VOICE_INPUT_DELIVERED));
+ }
+
+ public void textModified() {
+ mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED));
+ }
+
+ public void nBestChoose(int index) {
+ Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.N_BEST_CHOOSE);
+ i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index);
+ mContext.sendBroadcast(i);
+ }
+
+ public void inputEnded() {
+ mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.INPUT_ENDED));
+ }
+
+ public void voiceInputSettingEnabled() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_ENABLED));
+ }
+
+ public void voiceInputSettingDisabled() {
+ mContext.sendBroadcast(newLoggingBroadcast(
+ LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_DISABLED));
+ }
+}
diff --git a/src/com/android/inputmethod/voice/WaveformImage.java b/src/com/android/inputmethod/voice/WaveformImage.java
new file mode 100644
index 000000000..08d87c8f3
--- /dev/null
+++ b/src/com/android/inputmethod/voice/WaveformImage.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ *
+ * 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.voice;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+
+/**
+ * Utility class to draw a waveform into a bitmap, given a byte array
+ * that represents the waveform as a sequence of 16-bit integers.
+ * Adapted from RecognitionActivity.java.
+ */
+public class WaveformImage {
+ private static final int SAMPLING_RATE = 8000;
+
+ private WaveformImage() {}
+
+ public static Bitmap drawWaveform(
+ ByteArrayOutputStream waveBuffer, int w, int h, int start, int end) {
+ final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ final Canvas c = new Canvas(b);
+ final Paint paint = new Paint();
+ paint.setColor(0xFFFFFFFF); // 0xRRGGBBAA
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(0);
+
+ final ShortBuffer buf = ByteBuffer
+ .wrap(waveBuffer.toByteArray())
+ .order(ByteOrder.nativeOrder())
+ .asShortBuffer();
+ buf.position(0);
+
+ final int numSamples = waveBuffer.size() / 2;
+ final int delay = (SAMPLING_RATE * 100 / 1000);
+ int endIndex = end / 2 + delay;
+ if (end == 0 || endIndex >= numSamples) {
+ endIndex = numSamples;
+ }
+ int index = start / 2 - delay;
+ if (index < 0) {
+ index = 0;
+ }
+ final int size = endIndex - index;
+ int numSamplePerPixel = 32;
+ int delta = size / (numSamplePerPixel * w);
+ if (delta == 0) {
+ numSamplePerPixel = size / w;
+ delta = 1;
+ }
+
+ final float scale = 3.5f / 65536.0f;
+ // do one less column to make sure we won't read past
+ // the buffer.
+ try {
+ for (int i = 0; i < w - 1 ; i++) {
+ final float x = i;
+ for (int j = 0; j < numSamplePerPixel; j++) {
+ final short s = buf.get(index);
+ final float y = (h / 2) - (s * h * scale);
+ c.drawPoint(x, y, paint);
+ index += delta;
+ }
+ }
+ } catch (IndexOutOfBoundsException e) {
+ // this can happen, but we don't care
+ }
+
+ return b;
+ }
+}
diff --git a/src/com/android/inputmethod/voice/Whitelist.java b/src/com/android/inputmethod/voice/Whitelist.java
new file mode 100644
index 000000000..167b688ca
--- /dev/null
+++ b/src/com/android/inputmethod/voice/Whitelist.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.voice;
+
+import android.os.Bundle;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A set of text fields where speech has been explicitly enabled.
+ */
+public class Whitelist {
+ private List<Bundle> mConditions;
+
+ public Whitelist() {
+ mConditions = new ArrayList<Bundle>();
+ }
+
+ public Whitelist(List<Bundle> conditions) {
+ this.mConditions = conditions;
+ }
+
+ public void addApp(String app) {
+ Bundle bundle = new Bundle();
+ bundle.putString("packageName", app);
+ mConditions.add(bundle);
+ }
+
+ /**
+ * @return true if the field is a member of the whitelist.
+ */
+ public boolean matches(FieldContext context) {
+ for (Bundle condition : mConditions) {
+ if (matches(condition, context.getBundle())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return true of all values in condition are matched by a value
+ * in target.
+ */
+ private boolean matches(Bundle condition, Bundle target) {
+ for (String key : condition.keySet()) {
+ if (!condition.getString(key).equals(target.getString(key))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/com/google/android/voicesearch/LatinIMEWithVoice.java b/src/com/google/android/voicesearch/LatinIMEWithVoice.java
new file mode 100644
index 000000000..8a339d14a
--- /dev/null
+++ b/src/com/google/android/voicesearch/LatinIMEWithVoice.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.google.android.voicesearch;
+
+import android.content.Intent;
+
+import com.android.inputmethod.latin.LatinIME;
+
+public class LatinIMEWithVoice extends LatinIME {
+ @Override
+ protected void launchSettings() {
+ launchSettings(LatinIMEWithVoiceSettings.class);
+ }
+}
diff --git a/src/com/google/android/voicesearch/LatinIMEWithVoiceSettings.java b/src/com/google/android/voicesearch/LatinIMEWithVoiceSettings.java
new file mode 100644
index 000000000..a53cebfd9
--- /dev/null
+++ b/src/com/google/android/voicesearch/LatinIMEWithVoiceSettings.java
@@ -0,0 +1,5 @@
+package com.google.android.voicesearch;
+
+import com.android.inputmethod.latin.LatinIMESettings;
+
+public class LatinIMEWithVoiceSettings extends LatinIMESettings {}