diff options
42 files changed, 842 insertions, 656 deletions
diff --git a/dictionaries/es_wordlist.combined.gz b/dictionaries/es_wordlist.combined.gz Binary files differindex 181a958c0..c0a5264fc 100644 --- a/dictionaries/es_wordlist.combined.gz +++ b/dictionaries/es_wordlist.combined.gz diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index 6f4e602ce..5d8ef43f5 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -86,7 +86,7 @@ </receiver> <activity android:name=".settings.SettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/english_ime_settings" android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> @@ -95,7 +95,7 @@ </activity> <activity android:name=".spellcheck.SpellCheckerSettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/android_spell_checker_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -103,7 +103,7 @@ </activity> <activity android:name=".settings.DebugSettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/english_ime_debug_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -150,7 +150,7 @@ </receiver> <activity android:name="com.android.inputmethod.dictionarypack.DictionarySettingsActivity" - android:theme="@style/platformActivityTheme" + android:theme="@style/platformSettingsTheme" android:label="@string/dictionary_settings_title" android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> diff --git a/java/res/layout/key_preview.xml b/java/res/layout/key_preview.xml deleted file mode 100644 index 16d4c72c3..000000000 --- a/java/res/layout/key_preview.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2013, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minWidth="32dp" - android:gravity="center" - style="?attr/keyPreviewTextViewStyle" -/> diff --git a/java/res/raw/main_es.dict b/java/res/raw/main_es.dict Binary files differindex 83eefe4f6..0911b70f1 100644 --- a/java/res/raw/main_es.dict +++ b/java/res/raw/main_es.dict diff --git a/java/res/values-v20/platform-theme.xml b/java/res/values-v21/platform-theme.xml index 52e7f3521..a49e36459 100644 --- a/java/res/values-v20/platform-theme.xml +++ b/java/res/values-v21/platform-theme.xml @@ -18,9 +18,21 @@ */ --> -<!-- TODO: This file is temporarily placed under values-v20. --> -<!-- TODO: It might be moved under values-v21. --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="platformActivityTheme" parent="@android:style/Theme.Material.Light" /> + <!-- From packages/apps/Settings --> + <style name="platformSettingsTheme" parent="@android:style/Theme.Material.Settings"> + <item name="android:actionBarStyle">@android:style/Widget.Material.Light.ActionBar.Solid</item> + <item name="android:alertDialogTheme">@style/Theme.AlertDialog</item> + </style> + <!-- From packages/apps/Settings --> + <style name="Theme.AlertDialog" parent="@*android:style/Theme.Material.Light.Dialog.Alert"> + <!-- Used by the ActionBar: @color/theme_primary --> + <item name="android:colorPrimary">#ff263238</item> + <!-- Used by the StatusBar: @color/theme_primary_dark --> + <item name="android:colorPrimaryDark">#ff21272b</item> + <!-- Used by controls, e.g. CheckBox, ProgressBar, etc.: @color/theme_accent --> + <item name="android:colorAccent">#ff009688</item> + </style> <style name="platformDialogTheme" parent="@android:style/Theme.Material.Light.Dialog" /> </resources> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index a1f478bd5..fcb919d0b 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -26,8 +26,6 @@ <attr name="keyboardViewStyle" format="reference" /> <!-- MainKeyboardView style --> <attr name="mainKeyboardViewStyle" format="reference" /> - <!-- Key preview text view style --> - <attr name="keyPreviewTextViewStyle" format="reference"/> <!-- EmojiPalettesView style --> <attr name="emojiPalettesViewStyle" format="reference" /> <!-- MoreKeysKeyboard style --> @@ -106,8 +104,8 @@ <attr name="longPressShiftLockTimeout" format="integer" /> <!-- Ignore special key timeout while typing in millisecond. --> <attr name="ignoreAltCodeKeyTimeout" format="integer" /> - <!-- Layout resource for key press feedback.--> - <attr name="keyPreviewLayout" format="reference" /> + <!-- Background resource for key press feedback.--> + <attr name="keyPreviewBackground" format="reference" /> <!-- Vertical offset of the key press feedback from the key. --> <attr name="keyPreviewOffset" format="dimension" /> <!-- Height of the key press feedback popup. --> diff --git a/java/res/values/keyboard-themes.xml b/java/res/values/keyboard-themes.xml index a06082c6e..28a34c315 100644 --- a/java/res/values/keyboard-themes.xml +++ b/java/res/values/keyboard-themes.xml @@ -20,13 +20,14 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- For keyboard color scheme option dialog. --> <string-array name="keyboard_theme_names" translatable="false"> - <!-- TODO: Make this item as translatable string resource. --> - <item>Material</item> - <item>@string/keyboard_color_scheme_white</item> - <item>@string/keyboard_color_scheme_blue</item> + <!-- TODO: Implement Material Light theme. --> + <item>@string/keyboard_theme_material_dark</item> + <item>@string/keyboard_theme_holo_white</item> + <item>@string/keyboard_theme_holo_blue</item> </string-array> <!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. --> <string-array name="keyboard_theme_ids" translatable="false"> + <!-- TODO: Implement Material Light theme. --> <item>3</item> <item>2</item> <item>0</item> diff --git a/java/res/values/platform-theme.xml b/java/res/values/platform-theme.xml index 8e131a2b0..e68859712 100644 --- a/java/res/values/platform-theme.xml +++ b/java/res/values/platform-theme.xml @@ -20,5 +20,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="platformActivityTheme" parent="@android:style/Theme.Holo" /> + <style name="platformSettingsTheme" parent="@android:style/Theme.Holo" /> <style name="platformDialogTheme" parent="@android:style/Theme.Holo.Dialog" /> </resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 884911565..9ec3f469c 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -36,22 +36,18 @@ <!-- Option to control whether or not to show a popup with a larger font on each key press. --> <string name="popup_on_keypress">Popup on keypress</string> - <!-- Category title for general settings for Android keyboard --> - <string name="general_category">General</string> - - <!-- Category title for text prediction --> - <string name="correction_category">Text correction</string> - - <!-- Category title for gesture typing --> - <string name="gesture_typing_category">Gesture typing</string> - - <!-- Category title for misc options --> - <string name="misc_category">Other options</string> - - <!-- Option name for advanced settings screen [CHAR LIMIT=25] --> - <string name="advanced_settings">Advanced settings</string> - <!-- Option summary for advanced settings screen [CHAR LIMIT=65 (two lines) or 30 (fits on one line, preferable)] --> - <string name="advanced_settings_summary">Options for experts</string> + <!-- Settings screen title for input preferences [CHAR LIMIT=25]--> + <string name="settings_screen_input">Input preferences</string> + <!-- Settings screen title for appearance preferences [CHAR LIMIT=25] --> + <string name="settings_screen_appearances">Appearance</string> + <!-- Settings screen title for multi lingual options [CHAR_LIMIT=25] --> + <string name="settings_screen_multi_lingual">Multi lingual options</string> + <!-- Settings screen title for gesture typing preferences [CHAR_LIMIT=25] --> + <string name="settings_screen_gesture">Gesture typing preferences</string> + <!-- Settings screen title for text correction options [CHAR_LIMIT=25] --> + <string name="settings_screen_correction">Text correction</string> + <!-- Settings screen title for advanced settings [CHAR LIMIT=25] --> + <string name="settings_screen_advanced">Advanced</string> <!-- Option name for including other IMEs in the language switch list [CHAR LIMIT=30] --> <string name="include_other_imes_in_language_switch_list">Switch to other input methods</string> @@ -295,12 +291,16 @@ mobile devices. [CHAR LIMIT=25] --> <!-- Description for Emoji keyboard subtype [CHAR LIMIT=25] --> <string name="subtype_emoji">Emoji</string> - <!-- Title of the preference settings for switching keyboard color scheme [CHAR LIMIT=35] --> - <string name="keyboard_color_scheme">Color scheme</string> - <!-- The keyboard color scheme name, White [CHAR LIMIT=16] --> - <string name="keyboard_color_scheme_white">White</string> - <!-- The keyboard color scheme name, Blue [CHAR LIMIT=16] --> - <string name="keyboard_color_scheme_blue">Blue</string> + <!-- Title of the preference settings for switching keyboard theme [CHAR LIMIT=35] --> + <string name="keyboard_theme">Keyboard theme</string> + <!-- The keyboard theme name, Holo White [CHAR LIMIT=25] --> + <string name="keyboard_theme_holo_white">Holo White</string> + <!-- The keyboard theme name, Holo Blue [CHAR LIMIT=25] --> + <string name="keyboard_theme_holo_blue">Holo Blue</string> + <!-- The keyboard theme name, Material Dark [CHAR LIMIT=25] --> + <string name="keyboard_theme_material_dark">Material Dark</string> + <!-- The keyboard theme name, Material Light [CHAR LIMIT=25] --> + <string name="keyboard_theme_material_light">Material Light</string> <!-- Title of the preference settings for custom input styles (language and keyboard layout pairs) [CHAR LIMIT=35]--> <string name="custom_input_styles_title">Custom input styles</string> diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml index 02a93ca82..2b2a80aed 100644 --- a/java/res/values/themes-common.xml +++ b/java/res/values/themes-common.xml @@ -75,7 +75,6 @@ <item name="keyRepeatInterval">@integer/config_key_repeat_interval</item> <item name="longPressShiftLockTimeout">@integer/config_longpress_shift_lock_timeout</item> <item name="ignoreAltCodeKeyTimeout">@integer/config_ignore_alt_code_key_timeout</item> - <item name="keyPreviewLayout">@layout/key_preview</item> <item name="keyPreviewHeight">@dimen/config_key_preview_height</item> <!-- TODO: consolidate key preview linger timeout with the key preview animation parameters. --> <item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item> @@ -106,7 +105,6 @@ <style name="MainKeyboardView" parent="KeyboardView" /> - <style name="KeyPreviewTextView" /> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style name="EmojiPalettesView" /> diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml index 319b4aeed..073ae90b9 100644 --- a/java/res/values/themes-ics.xml +++ b/java/res/values/themes-ics.xml @@ -23,7 +23,6 @@ <item name="keyboardStyle">@style/Keyboard.ICS</item> <item name="keyboardViewStyle">@style/KeyboardView.ICS</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item> - <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.ICS</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.ICS</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.ICS</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.ICS</item> @@ -66,6 +65,7 @@ name="MainKeyboardView.ICS" parent="KeyboardView.ICS" > + <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_ics</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_ics</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> @@ -75,12 +75,6 @@ <item name="languageOnSpacebarTextShadowRadius">1.0</item> <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> </style> - <style - name="KeyPreviewTextView.ICS" - parent="KeyPreviewTextView" - > - <item name="android:background">@drawable/keyboard_key_feedback_ics</item> - </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml index 208723dd3..f895de572 100644 --- a/java/res/values/themes-klp.xml +++ b/java/res/values/themes-klp.xml @@ -23,7 +23,6 @@ <item name="keyboardStyle">@style/Keyboard.KLP</item> <item name="keyboardViewStyle">@style/KeyboardView.KLP</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.KLP</item> - <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.KLP</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.KLP</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.KLP</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.KLP</item> @@ -66,6 +65,7 @@ name="MainKeyboardView.KLP" parent="KeyboardView.KLP" > + <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_klp</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_klp</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> @@ -75,12 +75,6 @@ <item name="languageOnSpacebarTextShadowRadius">1.0</item> <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> </style> - <style - name="KeyPreviewTextView.KLP" - parent="KeyPreviewTextView" - > - <item name="android:background">@drawable/keyboard_key_feedback_klp</item> - </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style diff --git a/java/res/values/themes-lxx-dark.xml b/java/res/values/themes-lxx-dark.xml index e9a295c67..1db8f428e 100644 --- a/java/res/values/themes-lxx-dark.xml +++ b/java/res/values/themes-lxx-dark.xml @@ -23,7 +23,6 @@ <item name="keyboardStyle">@style/Keyboard.LXX_Dark</item> <item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark</item> - <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.LXX_Dark</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Dark</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark</item> @@ -67,6 +66,7 @@ name="MainKeyboardView.LXX_Dark" parent="KeyboardView.LXX_Dark" > + <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_lxx_dark</item> <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_lxx_dark</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_lxx_dark</item> @@ -76,12 +76,6 @@ <!-- A negative value to disable text shadow layer. --> <item name="languageOnSpacebarTextShadowRadius">-1.0</item> </style> - <style - name="KeyPreviewTextView.LXX_Dark" - parent="KeyPreviewTextView" - > - <item name="android:background">@drawable/keyboard_key_feedback_lxx_dark</item> - </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index 0e9c16190..cb951d264 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -18,39 +18,117 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" android:key="english_ime_settings"> - <PreferenceCategory - android:title="@string/general_category" - android:key="general_settings"> - <CheckBoxPreference + <PreferenceScreen + android:title="@string/settings_screen_input" + android:key="screen_input"> + <SwitchPreference android:key="auto_cap" android:title="@string/auto_cap" android:summary="@string/auto_cap_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - <CheckBoxPreference + <SwitchPreference + android:key="pref_key_use_double_space_period" + android:title="@string/use_double_space_period" + android:summary="@string/use_double_space_period_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference android:key="vibrate_on" android:title="@string/vibrate_on_keypress" - android:defaultValue="@bool/config_default_vibration_enabled" - android:persistent="true" /> - <CheckBoxPreference + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="@bool/config_default_vibration_enabled" /> + <SwitchPreference android:key="sound_on" android:title="@string/sound_on_keypress" - android:defaultValue="@bool/config_default_sound_enabled" - android:persistent="true" /> - <CheckBoxPreference + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="@bool/config_default_sound_enabled" /> + <SwitchPreference android:key="popup_on" android:title="@string/popup_on_keypress" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="@bool/config_default_key_preview_popup" /> - <CheckBoxPreference + <SwitchPreference android:key="pref_voice_input_key" android:title="@string/voice_input" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - </PreferenceCategory> - <PreferenceCategory - android:title="@string/correction_category" - android:key="correction_settings"> + </PreferenceScreen> + <ListPreference + android:key="pref_keyboard_theme" + android:title="@string/keyboard_theme" + android:persistent="true" + android:entryValues="@array/keyboard_theme_ids" + android:entries="@array/keyboard_theme_names" /> + <PreferenceScreen + android:title="@string/settings_screen_multi_lingual" + android:key="screen_multi_lingual"> + <SwitchPreference + android:key="pref_show_language_switch_key" + android:title="@string/show_language_switch_key" + android:summary="@string/show_language_switch_key_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference + android:key="pref_include_other_imes_in_language_switch_list" + android:dependency="pref_show_language_switch_key" + android:title="@string/include_other_imes_in_language_switch_list" + android:summary="@string/include_other_imes_in_language_switch_list_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="false" /> + <PreferenceScreen + android:fragment="com.android.inputmethod.latin.settings.AdditionalSubtypeSettings" + android:key="custom_input_styles" + android:title="@string/custom_input_styles_title" /> + </PreferenceScreen> + <PreferenceScreen + android:title="@string/settings_screen_gesture" + android:key="screen_gesture"> + <SwitchPreference + android:key="gesture_input" + android:title="@string/gesture_input" + android:summary="@string/gesture_input_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference + android:key="pref_gesture_floating_preview_text" + android:dependency="gesture_input" + android:title="@string/gesture_floating_preview_text" + android:summary="@string/gesture_floating_preview_text_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + <SwitchPreference + android:key="pref_gesture_preview_trail" + android:dependency="gesture_input" + android:title="@string/gesture_preview_trail" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + </PreferenceScreen> + <PreferenceScreen + android:title="@string/settings_screen_correction" + android:key="screen_correction"> <PreferenceScreen android:key="edit_personal_dictionary" android:title="@string/edit_personal_dictionary"> @@ -67,10 +145,12 @@ android:value="@string/dictionary_pack_client_id" /> </intent> </PreferenceScreen> - <CheckBoxPreference + <SwitchPreference android:key="pref_key_block_potentially_offensive" android:title="@string/prefs_block_potentially_offensive_title" android:summary="@string/prefs_block_potentially_offensive_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="@bool/config_block_potentially_offensive" /> <ListPreference @@ -89,119 +169,66 @@ android:entryValues="@array/prefs_suggestion_visibility_values" android:entries="@array/prefs_suggestion_visibilities" android:defaultValue="@string/prefs_suggestion_visibility_default_value" /> - <CheckBoxPreference + <SwitchPreference android:key="pref_key_use_personalized_dicts" android:title="@string/use_personalized_dicts" android:summary="@string/use_personalized_dicts_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - <!-- title will be set programmatically to embed application name --> - <CheckBoxPreference - android:key="pref_enable_metrics_logging" - android:summary="@string/enable_metrics_logging_summary" - android:persistent="true" - android:defaultValue="true" /> - </PreferenceCategory> - <PreferenceCategory - android:title="@string/gesture_typing_category" - android:key="gesture_typing_settings"> - <CheckBoxPreference - android:key="gesture_input" - android:title="@string/gesture_input" - android:summary="@string/gesture_input_summary" - android:persistent="true" - android:defaultValue="true" /> - <!-- TODO: Move these two options to the advanced settings. --> - <CheckBoxPreference - android:key="pref_gesture_floating_preview_text" - android:dependency="gesture_input" - android:title="@string/gesture_floating_preview_text" - android:summary="@string/gesture_floating_preview_text_summary" + <SwitchPreference + android:key="pref_key_use_contacts_dict" + android:title="@string/use_contacts_dict" + android:summary="@string/use_contacts_dict_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_gesture_preview_trail" - android:dependency="gesture_input" - android:title="@string/gesture_preview_trail" - android:persistent="true" - android:defaultValue="true" /> - </PreferenceCategory> - <PreferenceCategory - android:title="@string/misc_category" - android:key="misc_settings"> - <CheckBoxPreference + <SwitchPreference android:key="next_word_prediction" android:title="@string/bigram_prediction" android:summary="@string/bigram_prediction_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> + </PreferenceScreen> + <PreferenceScreen + android:title="@string/settings_screen_advanced" + android:key="screen_advanced"> + <!-- TODO: consolidate key preview dismiss delay with the key preview animation parameters. --> + <ListPreference + android:key="pref_key_preview_popup_dismiss_delay" + android:title="@string/key_preview_popup_dismiss_delay" /> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_vibration_duration_settings" + android:title="@string/prefs_keypress_vibration_duration_settings" + latin:maxValue="@integer/config_max_vibration_duration" /> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_keypress_sound_volume" + android:title="@string/prefs_keypress_sound_volume_settings" + latin:maxValue="100" /> <!-- percent --> + <!-- The settigs for showing setup wizard application icon shouldn't be persistent and + the default value is added programmatically. --> + <SwitchPreference + android:key="pref_show_setup_wizard_icon" + android:title="@string/show_setup_wizard_icon" + android:summary="@string/show_setup_wizard_icon_summary" + android:switchTextOn="" + android:switchTextOff="" /> + <!-- title will be set programmatically to embed application name --> + <SwitchPreference + android:key="pref_enable_metrics_logging" + android:summary="@string/enable_metrics_logging_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> <PreferenceScreen - android:key="pref_advanced_settings" - android:title="@string/advanced_settings" - android:summary="@string/advanced_settings_summary"> - <CheckBoxPreference - android:key="pref_key_use_contacts_dict" - android:title="@string/use_contacts_dict" - android:summary="@string/use_contacts_dict_summary" - android:persistent="true" - android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_key_use_double_space_period" - android:title="@string/use_double_space_period" - android:summary="@string/use_double_space_period_summary" - android:persistent="true" - android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_show_language_switch_key" - android:title="@string/show_language_switch_key" - android:summary="@string/show_language_switch_key_summary" - android:persistent="true" - android:defaultValue="true" /> - <CheckBoxPreference - android:key="pref_include_other_imes_in_language_switch_list" - android:dependency="pref_show_language_switch_key" - android:title="@string/include_other_imes_in_language_switch_list" - android:summary="@string/include_other_imes_in_language_switch_list_summary" - android:persistent="true" - android:defaultValue="false" /> - <ListPreference - android:key="pref_keyboard_theme" - android:title="@string/keyboard_color_scheme" - android:persistent="true" - android:entryValues="@array/keyboard_theme_ids" - android:entries="@array/keyboard_theme_names" /> - <PreferenceScreen - android:fragment="com.android.inputmethod.latin.settings.AdditionalSubtypeSettings" - android:key="custom_input_styles" - android:title="@string/custom_input_styles_title" /> - <!-- TODO: consolidate key preview dismiss delay with the key preview animation parameters. --> - <ListPreference - android:key="pref_key_preview_popup_dismiss_delay" - android:title="@string/key_preview_popup_dismiss_delay" /> - <com.android.inputmethod.latin.settings.SeekBarDialogPreference - android:key="pref_vibration_duration_settings" - android:title="@string/prefs_keypress_vibration_duration_settings" - latin:maxValue="@integer/config_max_vibration_duration" /> - <com.android.inputmethod.latin.settings.SeekBarDialogPreference - android:key="pref_keypress_sound_volume" - android:title="@string/prefs_keypress_sound_volume_settings" - latin:maxValue="100" /> <!-- percent --> - <!-- The settigs for showing setup wizard application icon shouldn't be persistent and - the default value is added programmatically. --> - <CheckBoxPreference - android:key="pref_show_setup_wizard_icon" - android:title="@string/show_setup_wizard_icon" - android:summary="@string/show_setup_wizard_icon_summary" /> - </PreferenceScreen> - <PreferenceScreen - android:key="send_feedback" - android:title="@string/send_feedback" /> - <PreferenceScreen - android:key="about_keyboard" /> - <PreferenceScreen - android:key="debug_settings" + android:key="screen_debug" android:title="Debug settings" android:persistent="true" android:defaultValue="false" /> - </PreferenceCategory> + </PreferenceScreen> </PreferenceScreen> diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml index 0bcc5cbe4..be4c8b3e1 100644 --- a/java/res/xml/prefs_for_debug.xml +++ b/java/res/xml/prefs_for_debug.xml @@ -20,20 +20,26 @@ android:title="@string/prefs_debug_mode" android:key="english_ime_debug_settings" > - <CheckBoxPreference + <SwitchPreference android:key="debug_mode" android:title="@string/prefs_debug_mode" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="false" /> - <CheckBoxPreference + <SwitchPreference android:key="force_non_distinct_multitouch" android:title="@string/prefs_force_non_distinct_multitouch" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="false" /> - <CheckBoxPreference + <SwitchPreference android:key="pref_sliding_key_input_preview" android:title="@string/sliding_key_input_preview" android:summary="@string/sliding_key_input_preview_summary" + android:switchTextOn="" + android:switchTextOff="" android:persistent="true" android:defaultValue="true" /> <com.android.inputmethod.latin.settings.SeekBarDialogPreference diff --git a/java/res/xml/spell_checker_settings.xml b/java/res/xml/spell_checker_settings.xml index de67e7f81..e3db4850b 100644 --- a/java/res/xml/spell_checker_settings.xml +++ b/java/res/xml/spell_checker_settings.xml @@ -15,11 +15,14 @@ --> <PreferenceScreen - xmlns:android="http://schemas.android.com/apk/res/android"> - <CheckBoxPreference - android:key="pref_spellcheck_use_contacts" - android:title="@string/use_contacts_for_spellchecking_option_title" - android:summary="@string/use_contacts_for_spellchecking_option_summary" - android:persistent="true" - android:defaultValue="true" /> + xmlns:android="http://schemas.android.com/apk/res/android" +> + <SwitchPreference + android:key="pref_spellcheck_use_contacts" + android:title="@string/use_contacts_for_spellchecking_option_title" + android:summary="@string/use_contacts_for_spellchecking_option_summary" + android:switchTextOn="" + android:switchTextOff="" + android:persistent="true" + android:defaultValue="true" /> </PreferenceScreen> diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java index d67d9dc4b..3925fc652 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java +++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java @@ -305,7 +305,7 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> key.onPressed(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); - provider.sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER); + provider.onHoverEnterTo(key); provider.performActionForKey(key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS); } @@ -328,6 +328,6 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> key.onReleased(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); - provider.sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT); + provider.onHoverExitFrom(key); } } diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java index cb13483f2..61d066af5 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java +++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java @@ -65,6 +65,9 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC /** The virtual view identifier for the focused node. */ private int mAccessibilityFocusedView = UNDEFINED; + /** The virtual view identifier for the hovering node. */ + private int mHoveringNodeId = UNDEFINED; + /** The current keyboard view. */ private final KeyboardView mKeyboardView; @@ -76,7 +79,6 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance(); mAccessibilityUtils = AccessibilityUtils.getInstance(); mKeyboardView = keyboardView; - updateParentLocation(); // Since this class is constructed lazily, we might not get a subsequent // call to setKeyboard() and therefore need to call it now. @@ -141,6 +143,28 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC return event; } + public void onHoverEnterTo(final Key key) { + final int id = getVirtualViewIdOf(key); + if (id == View.NO_ID) { + return; + } + // Start hovering on the key. Because our accessibility model is lift-to-type, we should + // report the node info without click and long click actions to avoid unnecessary + // announcements. + mHoveringNodeId = id; + // Invalidate the node info of the key. + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED); + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER); + } + + public void onHoverExitFrom(final Key key) { + mHoveringNodeId = UNDEFINED; + // Invalidate the node info of the key to be able to revert the change we have done + // in {@link #onHoverEnterTo(Key)}. + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED); + sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT); + } + /** * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or @@ -169,10 +193,23 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC } if (virtualViewId == View.NO_ID) { // We are requested to create an AccessibilityNodeInfo describing - // this View. Returning an empty info is sufficient for a keyboard. + // this View, i.e. the root of the virtual sub-tree. final AccessibilityNodeInfoCompat rootInfo = AccessibilityNodeInfoCompat.obtain(mKeyboardView); ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo); + updateParentLocation(); + + // Add the virtual children of the root View. + final List<Key> sortedKeys = mKeyboard.getSortedKeys(); + final int size = sortedKeys.size(); + for (int index = 0; index < size; index++) { + final Key key = sortedKeys.get(index); + if (key.isSpacer()) { + continue; + } + // Use an index of the sorted keys list as a virtual view id. + rootInfo.addChild(mKeyboardView, index); + } return rootInfo; } @@ -200,9 +237,16 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC info.setBoundsInScreen(boundsInScreen); info.setParent(mKeyboardView); info.setSource(mKeyboardView, virtualViewId); - info.setBoundsInScreen(boundsInScreen); - info.setEnabled(true); + info.setEnabled(key.isEnabled()); info.setVisibleToUser(true); + // Don't add ACTION_CLICK and ACTION_LONG_CLOCK actions while hovering on the key. + // See {@link #onHoverEnterTo(Key)} and {@link #onHoverExitFrom(Key)}. + if (virtualViewId != mHoveringNodeId) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK); + if (key.isLongPressEnabled()) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK); + } + } if (mAccessibilityFocusedView == virtualViewId) { info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS); @@ -241,6 +285,12 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC sendAccessibilityEventForKey( key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); return true; + case AccessibilityNodeInfoCompat.ACTION_CLICK: + sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_CLICKED); + return true; + case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK: + sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); + return true; default: return false; } diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index e7cfc453f..81825934f 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -236,16 +236,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); mGestureFloatingTextDrawingPreview = new GestureFloatingTextDrawingPreview( - mDrawingPreviewPlacerView, mainKeyboardViewAttr); - mDrawingPreviewPlacerView.addPreview(mGestureFloatingTextDrawingPreview); + mainKeyboardViewAttr); + mGestureFloatingTextDrawingPreview.setDrawingView(mDrawingPreviewPlacerView); - mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview( - mDrawingPreviewPlacerView, mainKeyboardViewAttr); - mDrawingPreviewPlacerView.addPreview(mGestureTrailsDrawingPreview); + mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview(mainKeyboardViewAttr); + mGestureTrailsDrawingPreview.setDrawingView(mDrawingPreviewPlacerView); - mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview( - mDrawingPreviewPlacerView, mainKeyboardViewAttr); - mDrawingPreviewPlacerView.addPreview(mSlidingKeyInputDrawingPreview); + mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview(mainKeyboardViewAttr); + mSlidingKeyInputDrawingPreview.setDrawingView(mDrawingPreviewPlacerView); mainKeyboardViewAttr.recycle(); mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) @@ -666,10 +664,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @Override public void onDismissMoreKeysPanel() { dimEntireKeyboard(false /* dimmed */); - dismissMoreKeysPanel(); - } - - private void dismissMoreKeysPanel() { if (isShowingMoreKeysPanel()) { mMoreKeysPanel.removeFromParent(); mMoreKeysPanel = null; @@ -735,7 +729,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } public void onHideWindow() { - dismissMoreKeysPanel(); + onDismissMoreKeysPanel(); final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate; if (accessibilityDelegate != null) { accessibilityDelegate.onHideWindow(); diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java index a34dbef4b..8010a3e7e 100644 --- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java @@ -21,6 +21,7 @@ import android.os.Handler; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; +import android.view.accessibility.AccessibilityEvent; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.KeyboardAccessibilityDelegate; @@ -106,6 +107,12 @@ final class EmojiPageKeyboardView extends KeyboardView implements } } + @Override + public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) { + // Don't populate accessibility event with all Emoji keys. + return true; + } + /** * {@inheritDoc} */ diff --git a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java index 3a72aed0d..a194f3dfd 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java @@ -27,16 +27,19 @@ import com.android.inputmethod.keyboard.PointerTracker; * SlidingKeyInputDrawingPreview. */ public abstract class AbstractDrawingPreview { - private final View mDrawingView; + private View mDrawingView; private boolean mPreviewEnabled; private boolean mHasValidGeometry; - protected AbstractDrawingPreview(final View drawingView) { + public void setDrawingView(final DrawingPreviewPlacerView drawingView) { mDrawingView = drawingView; + drawingView.addPreview(this); } - protected final View getDrawingView() { - return mDrawingView; + protected void invalidateDrawingView() { + if (mDrawingView != null) { + mDrawingView.invalidate(); + } } protected final boolean isPreviewEnabled() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java index 3b4c43418..a5d47adb3 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java @@ -46,7 +46,9 @@ public final class DrawingPreviewPlacerView extends RelativeLayout { } public void addPreview(final AbstractDrawingPreview preview) { - mPreviews.add(preview); + if (mPreviews.indexOf(preview) < 0) { + mPreviews.add(preview); + } } public void setKeyboardViewGeometry(final int[] originCoords, final int width, diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java index 2fa703083..fd84856b7 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java @@ -23,7 +23,6 @@ import android.graphics.Paint.Align; import android.graphics.Rect; import android.graphics.RectF; import android.text.TextUtils; -import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; @@ -49,6 +48,7 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { public final float mGesturePreviewHorizontalPadding; public final float mGesturePreviewVerticalPadding; public final float mGesturePreviewRoundRadius; + public final int mDisplayWidth; private final int mGesturePreviewTextSize; private final int mGesturePreviewTextColor; @@ -72,6 +72,7 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { R.styleable.MainKeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); mGesturePreviewRoundRadius = mainKeyboardViewAttr.getDimension( R.styleable.MainKeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); + mDisplayWidth = mainKeyboardViewAttr.getResources().getDisplayMetrics().widthPixels; final Paint textPaint = getTextPaint(); final Rect textRect = new Rect(); @@ -100,9 +101,8 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; private final int[] mLastPointerCoords = CoordinateUtils.newInstance(); - public GestureFloatingTextDrawingPreview(final View drawingView, final TypedArray typedArray) { - super(drawingView); - mParams = new GesturePreviewTextParams(typedArray); + public GestureFloatingTextDrawingPreview(final TypedArray mainKeyboardViewAttr) { + mParams = new GesturePreviewTextParams(mainKeyboardViewAttr); } @Override @@ -149,7 +149,7 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { */ protected void updatePreviewPosition() { if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) { - getDrawingView().invalidate(); + invalidateDrawingView(); return; } final String text = mSuggestedWords.getWord(0); @@ -163,10 +163,9 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { final float rectWidth = textWidth + hPad * 2.0f; final float rectHeight = textHeight + vPad * 2.0f; - final int displayWidth = getDrawingView().getResources().getDisplayMetrics().widthPixels; final float rectX = Math.min( Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f), - displayWidth - rectWidth); + mParams.mDisplayWidth - rectWidth); final float rectY = CoordinateUtils.y(mLastPointerCoords) - mParams.mGesturePreviewTextOffset - rectHeight; rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight); @@ -174,6 +173,6 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { mPreviewTextX = (int)(rectX + hPad + textWidth / 2.0f); mPreviewTextY = (int)(rectY + vPad) + textHeight; // TODO: Should narrow the invalidate region. - getDrawingView().invalidate(); + invalidateDrawingView(); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java index 72628e38a..f7bd7efe0 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java @@ -24,17 +24,15 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.os.Message; +import android.os.Handler; import android.util.SparseArray; -import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; -import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; /** * Draw preview graphics of multiple gesture trails during gesture input. */ -public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { +public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview implements Runnable { private final SparseArray<GestureTrailDrawingPoints> mGestureTrails = new SparseArray<>(); private final GestureTrailDrawingParams mDrawingParams; private final Paint mGesturePaint; @@ -47,45 +45,10 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { private final Rect mDirtyRect = new Rect(); private final Rect mGestureTrailBoundsRect = new Rect(); // per trail - private final DrawingHandler mDrawingHandler; + private final Handler mDrawingHandler = new Handler(); - private static final class DrawingHandler - extends LeakGuardHandlerWrapper<GestureTrailsDrawingPreview> { - private static final int MSG_UPDATE_GESTURE_TRAIL = 0; - - private final GestureTrailDrawingParams mDrawingParams; - - public DrawingHandler(final GestureTrailsDrawingPreview ownerInstance, - final GestureTrailDrawingParams drawingParams) { - super(ownerInstance); - mDrawingParams = drawingParams; - } - - @Override - public void handleMessage(final Message msg) { - final GestureTrailsDrawingPreview preview = getOwnerInstance(); - if (preview == null) { - return; - } - switch (msg.what) { - case MSG_UPDATE_GESTURE_TRAIL: - preview.getDrawingView().invalidate(); - break; - } - } - - public void postUpdateGestureTrailPreview() { - removeMessages(MSG_UPDATE_GESTURE_TRAIL); - sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_TRAIL), - mDrawingParams.mUpdateInterval); - } - } - - public GestureTrailsDrawingPreview(final View drawingView, - final TypedArray mainKeyboardViewAttr) { - super(drawingView); + public GestureTrailsDrawingPreview(final TypedArray mainKeyboardViewAttr) { mDrawingParams = new GestureTrailDrawingParams(mainKeyboardViewAttr); - mDrawingHandler = new DrawingHandler(this, mDrawingParams); final Paint gesturePaint = new Paint(); gesturePaint.setAntiAlias(true); gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); @@ -153,6 +116,12 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { return needsUpdatingGestureTrail; } + @Override + public void run() { + // Update preview. + invalidateDrawingView(); + } + /** * Draws the preview * @param canvas The canvas where the preview is drawn. @@ -167,7 +136,8 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { final boolean needsUpdatingGestureTrail = drawGestureTrails( mOffscreenCanvas, mGesturePaint, mDirtyRect); if (needsUpdatingGestureTrail) { - mDrawingHandler.postUpdateGestureTrailPreview(); + mDrawingHandler.removeCallbacks(this); + mDrawingHandler.postDelayed(this, mDrawingParams.mUpdateInterval); } // Transfer offscreen buffer to screen. if (!mDirtyRect.isEmpty()) { @@ -199,6 +169,6 @@ public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { trail.addStroke(tracker.getGestureStrokeDrawingPoints(), tracker.getDownTime()); // TODO: Should narrow the invalidate region. - getDrawingView().invalidate(); + invalidateDrawingView(); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java index d4c671028..6fc300beb 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -21,17 +21,12 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; -import android.graphics.drawable.Drawable; -import android.util.TypedValue; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; -import android.widget.TextView; import com.android.inputmethod.keyboard.Key; -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.ViewLayoutUtils; @@ -46,10 +41,11 @@ import java.util.HashSet; * - how key previews should be shown and dismissed. */ public final class KeyPreviewChoreographer { - // Free {@link TextView} pool that can be used for key preview. - private final ArrayDeque<TextView> mFreeKeyPreviewTextViews = new ArrayDeque<>(); - // Map from {@link Key} to {@link TextView} that is currently being displayed as key preview. - private final HashMap<Key,TextView> mShowingKeyPreviewTextViews = new HashMap<>(); + // Free {@link KeyPreviewView} pool that can be used for key preview. + private final ArrayDeque<KeyPreviewView> mFreeKeyPreviewViews = new ArrayDeque<>(); + // Map from {@link Key} to {@link KeyPreviewView} that is currently being displayed as key + // preview. + private final HashMap<Key,KeyPreviewView> mShowingKeyPreviewViews = new HashMap<>(); private final KeyPreviewDrawParams mParams; @@ -57,32 +53,28 @@ public final class KeyPreviewChoreographer { mParams = params; } - private TextView getKeyPreviewTextView(final Key key, final ViewGroup placerView) { - TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); - if (previewTextView != null) { - return previewTextView; + public KeyPreviewView getKeyPreviewView(final Key key, final ViewGroup placerView) { + KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.remove(key); + if (keyPreviewView != null) { + return keyPreviewView; } - previewTextView = mFreeKeyPreviewTextViews.poll(); - if (previewTextView != null) { - return previewTextView; + keyPreviewView = mFreeKeyPreviewViews.poll(); + if (keyPreviewView != null) { + return keyPreviewView; } final Context context = placerView.getContext(); - if (mParams.mLayoutId != 0) { - previewTextView = (TextView)LayoutInflater.from(context) - .inflate(mParams.mLayoutId, null); - } else { - previewTextView = new TextView(context); - } - placerView.addView(previewTextView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0)); - return previewTextView; + keyPreviewView = new KeyPreviewView(context, null /* attrs */); + keyPreviewView.setBackgroundResource(mParams.mPreviewBackgroundResId); + placerView.addView(keyPreviewView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0)); + return keyPreviewView; } public boolean isShowingKeyPreview(final Key key) { - return mShowingKeyPreviewTextViews.containsKey(key); + return mShowingKeyPreviewViews.containsKey(key); } public void dismissAllKeyPreviews() { - for (final Key key : new HashSet<>(mShowingKeyPreviewTextViews.keySet())) { + for (final Key key : new HashSet<>(mShowingKeyPreviewViews.keySet())) { dismissKeyPreview(key, false /* withAnimation */); } } @@ -91,11 +83,11 @@ public final class KeyPreviewChoreographer { if (key == null) { return; } - final TextView previewTextView = mShowingKeyPreviewTextViews.get(key); - if (previewTextView == null) { + final KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.get(key); + if (keyPreviewView == null) { return; } - final Object tag = previewTextView.getTag(); + final Object tag = keyPreviewView.getTag(); if (withAnimation) { if (tag instanceof KeyPreviewAnimations) { final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; @@ -104,114 +96,76 @@ public final class KeyPreviewChoreographer { } } // Dismiss preview without animation. - mShowingKeyPreviewTextViews.remove(key); + mShowingKeyPreviewViews.remove(key); if (tag instanceof Animator) { ((Animator)tag).cancel(); } - previewTextView.setTag(null); - previewTextView.setVisibility(View.INVISIBLE); - mFreeKeyPreviewTextViews.add(previewTextView); + keyPreviewView.setTag(null); + keyPreviewView.setVisibility(View.INVISIBLE); + mFreeKeyPreviewViews.add(keyPreviewView); } - // Background state set - private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { - { // STATE_MIDDLE - {}, - { R.attr.state_has_morekeys } - }, - { // STATE_LEFT - { R.attr.state_left_edge }, - { R.attr.state_left_edge, R.attr.state_has_morekeys } - }, - { // STATE_RIGHT - { R.attr.state_right_edge }, - { R.attr.state_right_edge, R.attr.state_has_morekeys } - } - }; - private static final int STATE_MIDDLE = 0; - private static final int STATE_LEFT = 1; - private static final int STATE_RIGHT = 2; - private static final int STATE_NORMAL = 0; - private static final int STATE_HAS_MOREKEYS = 1; - public void placeKeyPreviewAndShow(final Key key, final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams, final int keyboardViewWidth, final int[] keyboardOrigin, final ViewGroup placerView, final boolean withAnimation) { - final TextView previewTextView = getKeyPreviewTextView(key, placerView); + final KeyPreviewView keyPreviewView = getKeyPreviewView(key, placerView); placeKeyPreview( - key, previewTextView, iconsSet, drawParams, keyboardViewWidth, keyboardOrigin); - showKeyPreview(key, previewTextView, withAnimation); + key, keyPreviewView, iconsSet, drawParams, keyboardViewWidth, keyboardOrigin); + showKeyPreview(key, keyPreviewView, withAnimation); } - private void placeKeyPreview(final Key key, final TextView previewTextView, + private void placeKeyPreview(final Key key, final KeyPreviewView keyPreviewView, final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams, final int keyboardViewWidth, final int[] originCoords) { - previewTextView.setTextColor(drawParams.mPreviewTextColor); - final Drawable background = previewTextView.getBackground(); - final String label = key.getPreviewLabel(); - // What we show as preview should match what we show on a key top in onDraw(). - if (label != null) { - // TODO Should take care of temporaryShiftLabel here. - previewTextView.setCompoundDrawables(null, null, null, null); - previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, - key.selectPreviewTextSize(drawParams)); - previewTextView.setTypeface(key.selectPreviewTypeface(drawParams)); - previewTextView.setText(label); - } else { - previewTextView.setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet)); - previewTextView.setText(null); - } - - previewTextView.measure( + keyPreviewView.setPreviewVisual(key, iconsSet, drawParams); + keyPreviewView.measure( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - mParams.setGeometry(previewTextView); - final int previewWidth = previewTextView.getMeasuredWidth(); + mParams.setGeometry(keyPreviewView); + final int previewWidth = keyPreviewView.getMeasuredWidth(); final int previewHeight = mParams.mPreviewHeight; final int keyDrawWidth = key.getDrawWidth(); // The key preview is horizontally aligned with the center of the visible part of the // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and // the left/right background is used if such background is specified. - final int statePosition; + final int keyPreviewPosition; int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 + CoordinateUtils.x(originCoords); if (previewX < 0) { previewX = 0; - statePosition = STATE_LEFT; + keyPreviewPosition = KeyPreviewView.POSITION_LEFT; } else if (previewX > keyboardViewWidth - previewWidth) { previewX = keyboardViewWidth - previewWidth; - statePosition = STATE_RIGHT; + keyPreviewPosition = KeyPreviewView.POSITION_RIGHT; } else { - statePosition = STATE_MIDDLE; + keyPreviewPosition = KeyPreviewView.POSITION_MIDDLE; } + final boolean hasMoreKeys = (key.getMoreKeys() != null); + keyPreviewView.setPreviewBackground(hasMoreKeys, keyPreviewPosition); // The key preview is placed vertically above the top edge of the parent key with an // arbitrary offset. final int previewY = key.getY() - previewHeight + mParams.mPreviewOffset + CoordinateUtils.y(originCoords); - if (background != null) { - final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; - background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); - } ViewLayoutUtils.placeViewAt( - previewTextView, previewX, previewY, previewWidth, previewHeight); - previewTextView.setPivotX(previewWidth / 2.0f); - previewTextView.setPivotY(previewHeight); + keyPreviewView, previewX, previewY, previewWidth, previewHeight); + keyPreviewView.setPivotX(previewWidth / 2.0f); + keyPreviewView.setPivotY(previewHeight); } - private void showKeyPreview(final Key key, final TextView previewTextView, + private void showKeyPreview(final Key key, final KeyPreviewView keyPreviewView, final boolean withAnimation) { if (!withAnimation) { - previewTextView.setVisibility(View.VISIBLE); - mShowingKeyPreviewTextViews.put(key, previewTextView); + keyPreviewView.setVisibility(View.VISIBLE); + mShowingKeyPreviewViews.put(key, keyPreviewView); return; } // Show preview with animation. - final Animator showUpAnimation = createShowUpAniation(key, previewTextView); - final Animator dismissAnimation = createDismissAnimation(key, previewTextView); + final Animator showUpAnimation = createShowUpAniation(key, keyPreviewView); + final Animator dismissAnimation = createDismissAnimation(key, keyPreviewView); final KeyPreviewAnimations animation = new KeyPreviewAnimations( showUpAnimation, dismissAnimation); - previewTextView.setTag(animation); + keyPreviewView.setTag(animation); animation.startShowUp(); } @@ -221,13 +175,13 @@ public final class KeyPreviewChoreographer { private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); - private Animator createShowUpAniation(final Key key, final TextView previewTextView) { + private Animator createShowUpAniation(final Key key, final KeyPreviewView keyPreviewView) { // TODO: Optimization for no scale animation and no duration. final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_X, mParams.getShowUpStartScale(), + keyPreviewView, View.SCALE_X, mParams.getShowUpStartScale(), KEY_PREVIEW_SHOW_UP_END_SCALE); final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_Y, mParams.getShowUpStartScale(), + keyPreviewView, View.SCALE_Y, mParams.getShowUpStartScale(), KEY_PREVIEW_SHOW_UP_END_SCALE); final AnimatorSet showUpAnimation = new AnimatorSet(); showUpAnimation.play(scaleXAnimation).with(scaleYAnimation); @@ -236,18 +190,18 @@ public final class KeyPreviewChoreographer { showUpAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(final Animator animation) { - showKeyPreview(key, previewTextView, false /* withAnimation */); + showKeyPreview(key, keyPreviewView, false /* withAnimation */); } }); return showUpAnimation; } - private Animator createDismissAnimation(final Key key, final TextView previewTextView) { + private Animator createDismissAnimation(final Key key, final KeyPreviewView keyPreviewView) { // TODO: Optimization for no scale animation and no duration. final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_X, mParams.getDismissEndScale()); + keyPreviewView, View.SCALE_X, mParams.getDismissEndScale()); final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( - previewTextView, View.SCALE_Y, mParams.getDismissEndScale()); + keyPreviewView, View.SCALE_Y, mParams.getDismissEndScale()); final AnimatorSet dismissAnimation = new AnimatorSet(); dismissAnimation.play(scaleXAnimation).with(scaleYAnimation); final int dismissDuration = Math.min( diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java index 37e5c889d..68c9831fa 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java @@ -23,9 +23,9 @@ import com.android.inputmethod.latin.R; public final class KeyPreviewDrawParams { // XML attributes of {@link MainKeyboardView}. - public final int mLayoutId; public final int mPreviewOffset; public final int mPreviewHeight; + public final int mPreviewBackgroundResId; private int mShowUpDuration; private int mDismissDuration; private float mShowUpStartScale; @@ -63,13 +63,10 @@ public final class KeyPreviewDrawParams { R.styleable.MainKeyboardView_keyPreviewOffset, 0); mPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( R.styleable.MainKeyboardView_keyPreviewHeight, 0); + mPreviewBackgroundResId = mainKeyboardViewAttr.getResourceId( + R.styleable.MainKeyboardView_keyPreviewBackground, 0); mLingerTimeout = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); - mLayoutId = mainKeyboardViewAttr.getResourceId( - R.styleable.MainKeyboardView_keyPreviewLayout, 0); - if (mLayoutId == 0) { - mShowPopup = false; - } } public void setVisibleOffset(final int previewVisibleOffset) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java new file mode 100644 index 000000000..360faf829 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.TextView; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.latin.R; + +/** + * The pop up key preview view. + */ +public class KeyPreviewView extends TextView { + public static final int POSITION_MIDDLE = 0; + public static final int POSITION_LEFT = 1; + public static final int POSITION_RIGHT = 2; + + public KeyPreviewView(final Context context, final AttributeSet attrs) { + this(context, attrs, 0); + } + + public KeyPreviewView(final Context context, final AttributeSet attrs, final int defStyleAttr) { + super(context, attrs, defStyleAttr); + setGravity(Gravity.CENTER); + } + + public void setPreviewVisual(final Key key, final KeyboardIconsSet iconsSet, + final KeyDrawParams drawParams) { + // What we show as preview should match what we show on a key top in onDraw(). + final int iconId = key.getIconId(); + if (iconId != KeyboardIconsSet.ICON_UNDEFINED) { + setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet)); + setText(null); + return; + } + + setCompoundDrawables(null, null, null, null); + setTextColor(drawParams.mPreviewTextColor); + setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams)); + setTypeface(key.selectPreviewTypeface(drawParams)); + // TODO Should take care of temporaryShiftLabel here. + setText(key.getPreviewLabel()); + } + + // Background state set + private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { + { // POSITION_MIDDLE + {}, + { R.attr.state_has_morekeys } + }, + { // POSITION_LEFT + { R.attr.state_left_edge }, + { R.attr.state_left_edge, R.attr.state_has_morekeys } + }, + { // POSITION_RIGHT + { R.attr.state_right_edge }, + { R.attr.state_right_edge, R.attr.state_has_morekeys } + } + }; + private static final int STATE_NORMAL = 0; + private static final int STATE_HAS_MOREKEYS = 1; + + public void setPreviewBackground(final boolean hasMoreKeys, final int position) { + final Drawable background = getBackground(); + if (background == null) { + return; + } + final int hasMoreKeysState = hasMoreKeys ? STATE_HAS_MOREKEYS : STATE_NORMAL; + background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[position][hasMoreKeysState]); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java index 76cb89160..ef4c74d61 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java @@ -20,7 +20,6 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; -import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; @@ -28,6 +27,11 @@ import com.android.inputmethod.latin.utils.CoordinateUtils; /** * Draw rubber band preview graphics during sliding key input. + * + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewColor + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewWidth + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewBodyRatio + * @attr ref R.styleable#MainKeyboardView_slidingKeyInputPreviewShadowRatio */ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview { private final float mPreviewBodyRadius; @@ -40,9 +44,7 @@ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview private final RoundedLine mRoundedLine = new RoundedLine(); private final Paint mPaint = new Paint(); - public SlidingKeyInputDrawingPreview(final View drawingView, - final TypedArray mainKeyboardViewAttr) { - super(drawingView); + public SlidingKeyInputDrawingPreview(final TypedArray mainKeyboardViewAttr) { final int previewColor = mainKeyboardViewAttr.getColor( R.styleable.MainKeyboardView_slidingKeyInputPreviewColor, 0); final float previewRadius = mainKeyboardViewAttr.getDimension( @@ -69,7 +71,7 @@ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview public void dismissSlidingKeyInputPreview() { mShowsSlidingKeyInputPreview = false; - getDrawingView().invalidate(); + invalidateDrawingView(); } /** @@ -99,6 +101,6 @@ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview tracker.getDownCoordinates(mPreviewFrom); tracker.getLastCoordinates(mPreviewTo); mShowsSlidingKeyInputPreview = true; - getDrawingView().invalidate(); + invalidateDrawingView(); } } diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index 845ddb377..c17e86892 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -21,14 +21,13 @@ import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.os.Process; -import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.preference.TwoStatePreference; -import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.DictionaryDumpBroadcastReceiver; import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.R; @@ -57,7 +56,7 @@ public final class DebugSettings extends PreferenceFragment public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout"; private boolean mServiceNeedsRestart = false; - private CheckBoxPreference mDebugMode; + private TwoStatePreference mDebugMode; @Override public void onCreate(Bundle icicle) { @@ -107,7 +106,7 @@ public final class DebugSettings extends PreferenceFragment res, R.fraction.config_key_preview_dismiss_end_scale)); mServiceNeedsRestart = false; - mDebugMode = (CheckBoxPreference) findPreference(PREF_DEBUG_MODE); + mDebugMode = (TwoStatePreference) findPreference(PREF_DEBUG_MODE); updateDebugMode(); } diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index 235847799..fb1a210bb 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -39,8 +39,14 @@ import java.util.concurrent.locks.ReentrantLock; public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = Settings.class.getSimpleName(); + // Settings screens + public static final String SCREEN_INPUT = "screen_input"; + public static final String SCREEN_MULTI_LINGUAL = "screen_multi_lingual"; + public static final String SCREEN_GESTURE = "screen_gesture"; + public static final String SCREEN_CORRECTION = "screen_correction"; + public static final String SCREEN_ADVANCED = "screen_advanced"; + public static final String SCREEN_DEBUG = "screen_debug"; // In the same order as xml/prefs.xml - public static final String PREF_GENERAL_SETTINGS = "general_settings"; public static final String PREF_AUTO_CAP = "auto_cap"; public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_SOUND_ON = "sound_on"; @@ -48,13 +54,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang // PREF_VOICE_MODE_OBSOLETE is obsolete. Use PREF_VOICE_INPUT_KEY instead. public static final String PREF_VOICE_MODE_OBSOLETE = "voice_mode"; public static final String PREF_VOICE_INPUT_KEY = "pref_voice_input_key"; - public static final String PREF_CORRECTION_SETTINGS = "correction_settings"; public static final String PREF_EDIT_PERSONAL_DICTIONARY = "edit_personal_dictionary"; public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key"; public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold"; public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting"; - public static final String PREF_MISC_SETTINGS = "misc_settings"; - public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; public static final String PREF_KEY_USE_PERSONALIZED_DICTS = "pref_key_use_personalized_dicts"; public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = @@ -75,7 +78,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction"; - public static final String PREF_GESTURE_SETTINGS = "gesture_typing_settings"; public static final String PREF_GESTURE_INPUT = "gesture_input"; public static final String PREF_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; @@ -89,7 +91,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_INPUT_LANGUAGE = "input_language"; public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; - public static final String PREF_DEBUG_SETTINGS = "debug_settings"; public static final String PREF_KEY_IS_INTERNAL = "pref_key_is_internal"; public static final String PREF_ENABLE_METRICS_LOGGING = "pref_enable_metrics_logging"; @@ -105,8 +106,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang "pref_last_used_personalization_dict_wiped_time"; private static final String PREF_CORPUS_HANDLES_FOR_PERSONALIZATION = "pref_corpus_handles_for_personalization"; - public static final String PREF_SEND_FEEDBACK = "send_feedback"; - public static final String PREF_ABOUT_KEYBOARD = "about_keyboard"; // Emoji public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys"; diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java index 5eb0377c7..9d824121c 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java @@ -27,13 +27,15 @@ import android.content.res.Resources; import android.media.AudioManager; import android.os.Build; import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.preference.TwoStatePreference; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.dictionarypack.DictionarySettingsActivity; @@ -61,6 +63,10 @@ public final class SettingsFragment extends InputMethodSettingsFragment DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS || Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2; + private static final int NO_MENU_GROUP = Menu.NONE; // We don't care about menu grouping. + private static final int MENU_FEEDBACK = Menu.FIRST; // The first menu item id and order. + private static final int MENU_ABOUT = Menu.FIRST + 1; // The second menu item id and order. + private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { final Preference preference = findPreference(preferenceKey); if (preference != null) { @@ -93,6 +99,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment @Override public void onCreate(final Bundle icicle) { super.onCreate(icicle); + setHasOptionsMenu(true); setInputMethodSettingsCategoryTitle(R.string.language_selection_title); setSubtypeEnablerTitle(R.string.select_language); addPreferencesFromResource(R.xml.prefs); @@ -117,66 +124,42 @@ public final class SettingsFragment extends InputMethodSettingsFragment ensureConsistencyOfAutoCorrectionSettings(); - final PreferenceGroup generalSettings = - (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS); - final PreferenceGroup miscSettings = - (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS); - - final Preference debugSettings = findPreference(Settings.PREF_DEBUG_SETTINGS); - if (debugSettings != null) { - if (Settings.isInternal(prefs)) { - final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); - debugSettingsIntent.setClassName( - context.getPackageName(), DebugSettingsActivity.class.getName()); - debugSettings.setIntent(debugSettingsIntent); - } else { - miscSettings.removePreference(debugSettings); - } - } - - final Preference feedbackSettings = findPreference(Settings.PREF_SEND_FEEDBACK); - final Preference aboutSettings = findPreference(Settings.PREF_ABOUT_KEYBOARD); - if (feedbackSettings != null) { - if (FeedbackUtils.isFeedbackFormSupported()) { - feedbackSettings.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(final Preference pref) { - FeedbackUtils.showFeedbackForm(getActivity()); - return true; - } - }); - aboutSettings.setTitle(FeedbackUtils.getAboutKeyboardTitleResId()); - aboutSettings.setIntent(FeedbackUtils.getAboutKeyboardIntent(getActivity())); - } else { - miscSettings.removePreference(feedbackSettings); - miscSettings.removePreference(aboutSettings); - } + final PreferenceScreen inputScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_INPUT); + final PreferenceScreen advancedScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_ADVANCED); + final Preference debugScreen = findPreference(Settings.SCREEN_DEBUG); + if (Settings.isInternal(prefs)) { + final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); + debugSettingsIntent.setClassName( + context.getPackageName(), DebugSettingsActivity.class.getName()); + debugScreen.setIntent(debugSettingsIntent); + } else { + advancedScreen.removePreference(debugScreen); } final boolean showVoiceKeyOption = res.getBoolean( R.bool.config_enable_show_voice_key_option); if (!showVoiceKeyOption) { - removePreference(Settings.PREF_VOICE_INPUT_KEY, generalSettings); + removePreference(Settings.PREF_VOICE_INPUT_KEY, inputScreen); } - final PreferenceGroup advancedSettings = - (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS); if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { - removePreference(Settings.PREF_VIBRATE_ON, generalSettings); - removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedSettings); + removePreference(Settings.PREF_VIBRATE_ON, inputScreen); + removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedScreen); } if (!Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS) { + final PreferenceScreen multiLingualScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_MULTI_LINGUAL); + removePreference(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, multiLingualScreen); removePreference( - Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, advancedSettings); - removePreference( - Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, advancedSettings); + Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, multiLingualScreen); } - // TODO: consolidate key preview dismiss delay with the key preview animation parameters. if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) { - removePreference(Settings.PREF_POPUP_ON, generalSettings); - removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedSettings); + removePreference(Settings.PREF_POPUP_ON, inputScreen); + removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedScreen); } else { // TODO: Cleanup this setup. final ListPreference keyPreviewPopupDismissDelay = @@ -199,18 +182,18 @@ public final class SettingsFragment extends InputMethodSettingsFragment } if (!res.getBoolean(R.bool.config_setup_wizard_available)) { - removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedSettings); + removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedScreen); } - final PreferenceGroup textCorrectionGroup = - (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); + final PreferenceScreen correctionScreen = + (PreferenceScreen) findPreference(Settings.SCREEN_CORRECTION); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); final Intent intent = dictionaryLink.getIntent(); intent.setClassName(context.getPackageName(), DictionarySettingsActivity.class.getName()); final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); if (0 >= number) { - textCorrectionGroup.removePreference(dictionaryLink); + correctionScreen.removePreference(dictionaryLink); } if (ProductionFlag.IS_METRICS_LOGGING_SUPPORTED) { @@ -224,7 +207,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment enableMetricsLogging.setTitle(enableMetricsLoggingTitle); } } else { - removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, textCorrectionGroup); + removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, advancedScreen); } final Preference editPersonalDictionary = @@ -238,7 +221,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment } if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) { - removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen()); + removePreference(Settings.SCREEN_GESTURE, getPreferenceScreen()); } AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this); @@ -261,8 +244,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment voiceInputKeyOption.setSummary(isShortcutImeEnabled ? null : res.getText(R.string.voice_input_disabled_summary)); } - final CheckBoxPreference showSetupWizardIcon = - (CheckBoxPreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); + final TwoStatePreference showSetupWizardIcon = + (TwoStatePreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); if (showSetupWizardIcon != null) { showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity())); } @@ -476,4 +459,29 @@ public final class SettingsFragment extends InputMethodSettingsFragment userDictionaryPreference.setFragment(UserDictionaryList.class.getName()); } } + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + if (!FeedbackUtils.isFeedbackFormSupported()) { + return; + } + menu.add(NO_MENU_GROUP, MENU_FEEDBACK /* itemId */, MENU_FEEDBACK /* order */, + R.string.send_feedback); + menu.add(NO_MENU_GROUP, MENU_ABOUT /* itemId */, MENU_ABOUT /* order */, + FeedbackUtils.getAboutKeyboardTitleResId()); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + final int itemId = item.getItemId(); + if (itemId == MENU_FEEDBACK) { + FeedbackUtils.showFeedbackForm(getActivity()); + return true; + } + if (itemId == MENU_ABOUT) { + startActivity(FeedbackUtils.getAboutKeyboardIntent(getActivity())); + return true; + } + return super.onOptionsItemSelected(item); + } } diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 47b5c3344..72f8f87e4 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -92,3 +92,6 @@ include $(LOCAL_PATH)/CleanupNativeFileList.mk #################### Unit test on host environment include $(LOCAL_PATH)/HostUnitTests.mk + +#################### Unit test on target environment +include $(LOCAL_PATH)/TargetUnitTests.mk diff --git a/native/jni/TargetUnitTests.mk b/native/jni/TargetUnitTests.mk new file mode 100644 index 000000000..12aae44ea --- /dev/null +++ b/native/jni/TargetUnitTests.mk @@ -0,0 +1,55 @@ +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +###################################### +include $(CLEAR_VARS) + +include $(LOCAL_PATH)/NativeFileList.mk + +#################### Target library for unit test +LATIN_IME_SRC_DIR := src +LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function +LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) +LOCAL_MODULE := liblatinime_target_static_for_unittests +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := $(addprefix $(LATIN_IME_SRC_DIR)/, $(LATIN_IME_CORE_SRC_FILES)) +# Here intentionally use libc++_shared rather than libc++_static because +# $(BUILD_NATIVE_TEST) has not yet supported libc++_static. +LOCAL_SDK_VERSION := 14 +LOCAL_NDK_STL_VARIANT := c++_shared +include $(BUILD_STATIC_LIBRARY) + +#################### Target native tests +include $(CLEAR_VARS) +LATIN_IME_TEST_SRC_DIR := tests +LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function +LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) +LOCAL_MODULE := liblatinime_target_unittests +LOCAL_MODULE_TAGS := tests +LOCAL_SRC_FILES := \ + $(addprefix $(LATIN_IME_TEST_SRC_DIR)/, $(LATIN_IME_CORE_TEST_FILES)) +LOCAL_STATIC_LIBRARIES += liblatinime_target_static_for_unittests +# Here intentionally include external/libcxx/libcxx.mk rather because +# $(BUILD_NATIVE_TEST) fails when LOCAL_NDK_STL_VARIANT is specified. +include external/libcxx/libcxx.mk +include $(BUILD_NATIVE_TEST) + +#################### Clean up the tmp vars +LATIN_IME_SRC_DIR := +LATIN_IME_TEST_SRC_DIR := +include $(LOCAL_PATH)/CleanupNativeFileList.mk diff --git a/native/jni/run-tests.sh b/native/jni/run-tests.sh index 5b60e0d65..3da45270d 100755 --- a/native/jni/run-tests.sh +++ b/native/jni/run-tests.sh @@ -13,17 +13,56 @@ # See the License for the specific language governing permissions and # limitations under the License. +function usage() { + echo "usage: source run-tests.sh [--host] [--target] [-h] [--help]" 1>&2 + echo " --host: run test on the host environment" 1>&2 + echo " --no-host: skip host test" 1>&2 + echo " --target: run test on the target environment" 1>&2 + echo " --no-target: skip target device test" 1>&2 +} + +# check script arguments if [[ $(type -t mmm) != function ]]; then -echo "Usage:" 1>&2 -echo " source $0" 1>&2 -echo " or" 1>&2 -echo " . $0" 1>&2 +usage if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi fi +show_usage=no +enable_host_test=yes +enable_target_device_test=no +while [ "$1" != "" ] + do + case "$1" in + "-h") show_usage=yes;; + "--help") show_usage=yes;; + "--target") enable_target_device_test=yes;; + "--no-target") enable_target_device_test=no;; + "--host") enable_host_test=yes;; + "--no-host") enable_host_test=no;; + esac + shift +done + +if [[ $show_usage == yes ]]; then + usage + if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi +fi + +target_test_name=liblatinime_target_unittests +host_test_name=liblatinime_host_unittests + pushd $PWD > /dev/null cd $(gettop) mmm -j16 packages/inputmethods/LatinIME/native/jni || \ - make -j16 liblatinime_host_unittests -${ANDROID_HOST_OUT}/bin/liblatinime_host_unittests -popd > /dev/null
\ No newline at end of file + make -j16 adb $target_test_name $host_test_name +if [[ $enable_host_test == yes ]]; then + $ANDROID_HOST_OUT/bin/$host_test_name +fi +if [[ $enable_target_device_test == yes ]]; then + target_test_local=$ANDROID_PRODUCT_OUT/data/nativetest/$target_test_name/$target_test_name + target_test_device=/data/nativetest/$target_test_name/$target_test_name + adb push $target_test_local $target_test_device + adb shell $target_test_device + adb shell rm -rf $target_test_device +fi +popd > /dev/null diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java index 2cbc04154..3ef03f4bd 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java @@ -26,11 +26,13 @@ import org.xml.sax.SAXException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; @@ -51,14 +53,17 @@ public final class BinaryDictOffdeviceUtils { public final static String ENCRYPTION = "encrypted"; private final static int MAX_DECODE_DEPTH = 8; + private final static int COPY_BUFFER_SIZE = 8192; public static class DecoderChainSpec { ArrayList<String> mDecoderSpec = new ArrayList<>(); File mFile; + public DecoderChainSpec addStep(final String stepDescription) { mDecoderSpec.add(stepDescription); return this; } + public String describeChain() { final StringBuilder s = new StringBuilder("raw"); for (final String step : mDecoderSpec) { @@ -70,13 +75,10 @@ public final class BinaryDictOffdeviceUtils { } public static void copy(final InputStream input, final OutputStream output) throws IOException { - final byte[] buffer = new byte[1000]; - final BufferedInputStream in = new BufferedInputStream(input); - final BufferedOutputStream out = new BufferedOutputStream(output); - for (int readBytes = in.read(buffer); readBytes >= 0; readBytes = in.read(buffer)) + final byte[] buffer = new byte[COPY_BUFFER_SIZE]; + for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer)) { output.write(buffer, 0, readBytes); - in.close(); - out.close(); + } } /** @@ -131,11 +133,15 @@ public final class BinaryDictOffdeviceUtils { try { final File dst = File.createTempFile(PREFIX, SUFFIX); dst.deleteOnExit(); - final FileOutputStream dstStream = new FileOutputStream(dst); - copy(Compress.getUncompressedStream(new BufferedInputStream(new FileInputStream(src))), - new BufferedOutputStream(dstStream)); // #copy() closes the streams - return dst; - } catch (IOException e) { + try ( + final InputStream input = Compress.getUncompressedStream( + new BufferedInputStream(new FileInputStream(src))); + final OutputStream output = new BufferedOutputStream(new FileOutputStream(dst)) + ) { + copy(input, output); + return dst; + } + } catch (final IOException e) { // Could not uncompress the file: presumably the file is simply not a compressed file return null; } @@ -150,20 +156,20 @@ public final class BinaryDictOffdeviceUtils { try { final File dst = File.createTempFile(PREFIX, SUFFIX); dst.deleteOnExit(); - final FileOutputStream dstStream = new FileOutputStream(dst); - copy(Crypt.getDecryptedStream(new BufferedInputStream(new FileInputStream(src))), - dstStream); // #copy() closes the streams - return dst; - } catch (IOException e) { + try ( + final InputStream input = Crypt.getDecryptedStream( + new BufferedInputStream(new FileInputStream(src))); + final OutputStream output = new BufferedOutputStream(new FileOutputStream(dst)) + ) { + copy(input, output); + return dst; + } + } catch (final IOException e) { // Could not decrypt the file: presumably the file is simply not a crypted file return null; } } - static void crash(final String filename, final Exception e) { - throw new RuntimeException("Can't read file " + filename, e); - } - static FusionDictionary getDictionary(final String filename, final boolean report) { final File file = new File(filename); if (report) { @@ -172,45 +178,40 @@ public final class BinaryDictOffdeviceUtils { } try { if (XmlDictInputOutput.isXmlUnigramDictionary(filename)) { - if (report) System.out.println("Format : XML unigram list"); + if (report) { + System.out.println("Format : XML unigram list"); + } return XmlDictInputOutput.readDictionaryXml( new BufferedInputStream(new FileInputStream(file)), null /* shortcuts */, null /* bigrams */); - } else { - final DecoderChainSpec decodedSpec = getRawDictionaryOrNull(file); - if (null == decodedSpec) { - crash(filename, new RuntimeException( - filename + " does not seem to be a dictionary file")); - } else if (CombinedInputOutput.isCombinedDictionary( - decodedSpec.mFile.getAbsolutePath())){ - if (report) { - System.out.println("Format : Combined format"); - System.out.println("Packaging : " + decodedSpec.describeChain()); - System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); - } - return CombinedInputOutput.readDictionaryCombined( - new BufferedInputStream(new FileInputStream(decodedSpec.mFile))); - } else { - final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder( - decodedSpec.mFile, 0, decodedSpec.mFile.length(), - DictDecoder.USE_BYTEARRAY); - if (report) { - System.out.println("Format : Binary dictionary format"); - System.out.println("Packaging : " + decodedSpec.describeChain()); - System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); - } - return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); + } + final DecoderChainSpec decodedSpec = getRawDictionaryOrNull(file); + if (null == decodedSpec) { + throw new RuntimeException("Does not seem to be a dictionary file " + filename); + } + if (CombinedInputOutput.isCombinedDictionary(decodedSpec.mFile.getAbsolutePath())) { + if (report) { + System.out.println("Format : Combined format"); + System.out.println("Packaging : " + decodedSpec.describeChain()); + System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); } + try (final BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(decodedSpec.mFile), "UTF-8"))) { + return CombinedInputOutput.readDictionaryCombined(reader); + } + } + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder( + decodedSpec.mFile, 0, decodedSpec.mFile.length(), + DictDecoder.USE_BYTEARRAY); + if (report) { + System.out.println("Format : Binary dictionary format"); + System.out.println("Packaging : " + decodedSpec.describeChain()); + System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); } - } catch (IOException e) { - crash(filename, e); - } catch (SAXException e) { - crash(filename, e); - } catch (ParserConfigurationException e) { - crash(filename, e); - } catch (UnsupportedFormatException e) { - crash(filename, e); + return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); + } catch (final IOException | SAXException | ParserConfigurationException | + UnsupportedFormatException e) { + throw new RuntimeException("Can't read file " + filename, e); } - return null; } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java index 6a0e1b7f0..23cbee81c 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java @@ -26,13 +26,9 @@ import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.utils.CombinedFormatUtils; import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; +import java.io.BufferedWriter; import java.io.FileReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.TreeSet; @@ -57,27 +53,15 @@ public class CombinedInputOutput { * @return true if the file is in the combined format, false otherwise */ public static boolean isCombinedDictionary(final String filename) { - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(new File(filename))); + try (final BufferedReader reader = new BufferedReader(new FileReader(filename))) { String firstLine = reader.readLine(); while (firstLine.startsWith(COMMENT_LINE_STARTER)) { firstLine = reader.readLine(); } return firstLine.matches( "^" + CombinedFormatUtils.DICTIONARY_TAG + "=[^:]+(:[^=]+=[^:]+)*"); - } catch (FileNotFoundException e) { + } catch (final IOException e) { return false; - } catch (IOException e) { - return false; - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - // do nothing - } - } } } @@ -87,12 +71,11 @@ public class CombinedInputOutput { * This is the public method that will read a combined file and return the corresponding memory * representation. * - * @param source the file to read the data from. + * @param reader the buffered reader to read the data from. * @return the in-memory representation of the dictionary. */ - public static FusionDictionary readDictionaryCombined(final InputStream source) + public static FusionDictionary readDictionaryCombined(final BufferedReader reader) throws IOException { - final BufferedReader reader = new BufferedReader(new InputStreamReader(source, "UTF-8")); String headerLine = reader.readLine(); while (headerLine.startsWith(COMMENT_LINE_STARTER)) { headerLine = reader.readLine(); @@ -218,11 +201,11 @@ public class CombinedInputOutput { /** * Writes a dictionary to a combined file. * - * @param destination a destination stream to write to. + * @param destination a destination writer. * @param dict the dictionary to write. */ - public static void writeDictionaryCombined( - final Writer destination, final FusionDictionary dict) throws IOException { + public static void writeDictionaryCombined(final BufferedWriter destination, + final FusionDictionary dict) throws IOException { final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<>(); for (final WordProperty wordProperty : dict) { // This for ordering by frequency, then by asciibetic order @@ -232,6 +215,5 @@ public class CombinedInputOutput { for (final WordProperty wordProperty : wordPropertiesInDict) { destination.write(CombinedFormatUtils.formatWordProperty(wordProperty)); } - destination.close(); } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java index b7f48b522..728a159a0 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Compress.java @@ -16,11 +16,6 @@ package com.android.inputmethod.latin.dicttool; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -32,8 +27,7 @@ public class Compress { // This container class is not publicly instantiable. } - public static OutputStream getCompressedStream(final OutputStream out) - throws java.io.IOException { + public static OutputStream getCompressedStream(final OutputStream out) throws IOException { return new GZIPOutputStream(out); } @@ -43,7 +37,6 @@ public class Compress { static public class Compressor extends Dicttool.Command { public static final String COMMAND = "compress"; - public static final String STDIN_OR_STDOUT = "-"; public Compressor() { } @@ -61,17 +54,18 @@ public class Compress { } final String inFilename = mArgs.length >= 1 ? mArgs[0] : STDIN_OR_STDOUT; final String outFilename = mArgs.length >= 2 ? mArgs[1] : STDIN_OR_STDOUT; - final InputStream input = inFilename.equals(STDIN_OR_STDOUT) ? System.in - : new BufferedInputStream(new FileInputStream(new File(inFilename))); - final OutputStream output = outFilename.equals(STDIN_OR_STDOUT) ? System.out - : new BufferedOutputStream(new FileOutputStream(new File(outFilename))); - BinaryDictOffdeviceUtils.copy(input, new GZIPOutputStream(output)); + try ( + final InputStream input = getFileInputStreamOrStdIn(inFilename); + final OutputStream compressedOutput = getCompressedStream( + getFileOutputStreamOrStdOut(outFilename)) + ) { + BinaryDictOffdeviceUtils.copy(input, compressedOutput); + } } } static public class Uncompressor extends Dicttool.Command { public static final String COMMAND = "uncompress"; - public static final String STDIN_OR_STDOUT = "-"; public Uncompressor() { } @@ -89,11 +83,13 @@ public class Compress { } final String inFilename = mArgs.length >= 1 ? mArgs[0] : STDIN_OR_STDOUT; final String outFilename = mArgs.length >= 2 ? mArgs[1] : STDIN_OR_STDOUT; - final InputStream input = inFilename.equals(STDIN_OR_STDOUT) ? System.in - : new BufferedInputStream(new FileInputStream(new File(inFilename))); - final OutputStream output = outFilename.equals(STDIN_OR_STDOUT) ? System.out - : new BufferedOutputStream(new FileOutputStream(new File(outFilename))); - BinaryDictOffdeviceUtils.copy(new GZIPInputStream(input), output); + try ( + final InputStream uncompressedInput = getUncompressedStream( + getFileInputStreamOrStdIn(inFilename)); + final OutputStream output = getFileOutputStreamOrStdOut(outFilename) + ) { + BinaryDictOffdeviceUtils.copy(uncompressedInput, output); + } } } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java index 37c8d4184..3d0557b5c 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java @@ -27,19 +27,23 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import com.android.inputmethod.latin.makedict.Ver4DictEncoder; +import org.xml.sax.SAXException; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.Arrays; import java.util.LinkedList; import javax.xml.parsers.ParserConfigurationException; -import org.xml.sax.SAXException; - /** * Main class/method for DictionaryMaker. */ @@ -279,22 +283,21 @@ public class DictionaryMaker { */ private static FusionDictionary readCombinedFile(final String combinedFilename) throws FileNotFoundException, IOException { - FileInputStream inStream = null; - try { - final File file = new File(combinedFilename); - inStream = new FileInputStream(file); - return CombinedInputOutput.readDictionaryCombined(inStream); - } finally { - if (null != inStream) { - try { - inStream.close(); - } catch (IOException e) { - // do nothing - } - } + try (final BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(combinedFilename), "UTF-8")) + ) { + return CombinedInputOutput.readDictionaryCombined(reader); } } + private static BufferedInputStream getBufferedFileInputStream(final String filename) + throws FileNotFoundException { + if (filename == null) { + return null; + } + return new BufferedInputStream(new FileInputStream(filename)); + } + /** * Read a dictionary from a unigram XML file, and optionally a bigram XML file. * @@ -310,12 +313,13 @@ public class DictionaryMaker { private static FusionDictionary readXmlFile(final String unigramXmlFilename, final String shortcutXmlFilename, final String bigramXmlFilename) throws FileNotFoundException, SAXException, IOException, ParserConfigurationException { - final FileInputStream unigrams = new FileInputStream(new File(unigramXmlFilename)); - final FileInputStream shortcuts = null == shortcutXmlFilename ? null : - new FileInputStream(new File(shortcutXmlFilename)); - final FileInputStream bigrams = null == bigramXmlFilename ? null : - new FileInputStream(new File(bigramXmlFilename)); - return XmlDictInputOutput.readDictionaryXml(unigrams, shortcuts, bigrams); + try ( + final BufferedInputStream unigrams = getBufferedFileInputStream(unigramXmlFilename); + final BufferedInputStream shortcuts = getBufferedFileInputStream(shortcutXmlFilename); + final BufferedInputStream bigrams = getBufferedFileInputStream(bigramXmlFilename); + ) { + return XmlDictInputOutput.readDictionaryXml(unigrams, shortcuts, bigrams); + } } /** @@ -374,8 +378,9 @@ public class DictionaryMaker { */ private static void writeXmlDictionary(final String outputFilename, final FusionDictionary dict) throws FileNotFoundException, IOException { - XmlDictInputOutput.writeDictionaryXml(new BufferedWriter(new FileWriter(outputFilename)), - dict); + try (final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilename))) { + XmlDictInputOutput.writeDictionaryXml(writer, dict); + } } /** @@ -388,7 +393,8 @@ public class DictionaryMaker { */ private static void writeCombinedDictionary(final String outputFilename, final FusionDictionary dict) throws FileNotFoundException, IOException { - CombinedInputOutput.writeDictionaryCombined( - new BufferedWriter(new FileWriter(outputFilename)), dict); + try (final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilename))) { + CombinedInputOutput.writeDictionaryCombined(writer, dict); + } } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java index 8ae035f64..e49b35084 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java @@ -16,23 +16,63 @@ package com.android.inputmethod.latin.dicttool; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Arrays; import java.util.HashMap; public class Dicttool { public static abstract class Command { + public static final String STDIN_OR_STDOUT = "-"; protected String[] mArgs; + public void setArgs(String[] args) throws IllegalArgumentException { mArgs = args; } + + protected static InputStream getFileInputStreamOrStdIn(final String inFilename) + throws FileNotFoundException { + if (STDIN_OR_STDOUT.equals(inFilename)) { + return System.in; + } + return getFileInputStream(new File(inFilename)); + } + + protected static InputStream getFileInputStream(final File inFile) + throws FileNotFoundException { + return new BufferedInputStream(new FileInputStream(inFile)); + } + + protected static OutputStream getFileOutputStreamOrStdOut(final String outFilename) + throws FileNotFoundException { + if (STDIN_OR_STDOUT.equals(outFilename)) { + return System.out; + } + return getFileOutputStream(new File(outFilename)); + } + + protected static OutputStream getFileOutputStream(final File outFile) + throws FileNotFoundException { + return new BufferedOutputStream(new FileOutputStream(outFile)); + } + abstract public String getHelp(); abstract public void run() throws Exception; } + static HashMap<String, Class<? extends Command>> sCommands = new HashMap<>(); + static { CommandList.populate(); } + public static void addCommand(final String commandName, final Class<? extends Command> cls) { sCommands.put(commandName, cls); } @@ -60,7 +100,7 @@ public class Dicttool { return sCommands.containsKey(commandName); } - private Command getCommand(final String[] arguments) { + private static Command getCommand(final String[] arguments) { final String commandName = arguments[0]; if (!isCommand(commandName)) { throw new RuntimeException("Unknown command : " + commandName); @@ -76,7 +116,7 @@ public class Dicttool { * @param arguments the arguments passed to dicttool. * @return 0 for success, an error code otherwise (always 1 at the moment) */ - private int execute(final String[] arguments) { + private static int execute(final String[] arguments) { final Command command = getCommand(arguments); try { command.run(); @@ -95,6 +135,6 @@ public class Dicttool { return; } // Exit with the success/error code from #execute() as status. - System.exit(new Dicttool().execute(arguments)); + System.exit(execute(arguments)); } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java index dff3387be..1f6798269 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java @@ -21,8 +21,9 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; public class Package { private Package() { @@ -86,9 +87,13 @@ public class Package { } System.out.println("Packaging : " + decodedSpec.describeChain()); System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); - final FileOutputStream dstStream = new FileOutputStream(new File(mArgs[1])); - BinaryDictOffdeviceUtils.copy(new BufferedInputStream( - new FileInputStream(decodedSpec.mFile)), new BufferedOutputStream(dstStream)); + try ( + final InputStream input = getFileInputStream(decodedSpec.mFile); + final OutputStream output = new BufferedOutputStream( + getFileOutputStreamOrStdOut(mArgs[1])) + ) { + BinaryDictOffdeviceUtils.copy(input, output); + } } } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java index 7435fa7d6..bdec44761 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java @@ -23,13 +23,16 @@ import com.android.inputmethod.latin.makedict.ProbabilityInfo; import com.android.inputmethod.latin.makedict.WeightedString; import com.android.inputmethod.latin.makedict.WordProperty; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import java.io.BufferedInputStream; import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; +import java.io.BufferedWriter; +import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.Writer; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.TreeSet; @@ -38,10 +41,6 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - /** * Reads and writes XML files for a FusionDictionary. * @@ -57,8 +56,6 @@ public class XmlDictInputOutput { private static final String WORD_ATTR = "word"; private static final String NOT_A_WORD_ATTR = "not_a_word"; - private static final String OPTIONS_KEY = "options"; - /** * SAX handler for a unigram XML file. */ @@ -120,7 +117,6 @@ public class XmlDictInputOutput { final String attrName = attrs.getLocalName(attrIndex); attributes.put(attrName, attrs.getValue(attrIndex)); } - final String optionsString = attributes.get(OPTIONS_KEY); mDictionary = new FusionDictionary(new PtNodeArray(), new DictionaryOptions(attributes)); } else { @@ -244,14 +240,13 @@ public class XmlDictInputOutput { protected int getValueFromFreqString(final String freqString) { if (WHITELIST_MARKER.equals(freqString)) { return WHITELIST_FREQ_VALUE; - } else { - final int intValue = super.getValueFromFreqString(freqString); - if (intValue < MIN_FREQ || intValue > MAX_FREQ) { - throw new RuntimeException("Shortcut freq out of range. Accepted range is " - + MIN_FREQ + ".." + MAX_FREQ); - } - return intValue; } + final int intValue = super.getValueFromFreqString(freqString); + if (intValue < MIN_FREQ || intValue > MAX_FREQ) { + throw new RuntimeException("Shortcut freq out of range. Accepted range is " + + MIN_FREQ + ".." + MAX_FREQ); + } + return intValue; } // As per getAssocMap(), this never returns null. @@ -269,23 +264,12 @@ public class XmlDictInputOutput { * @return true if the file is in the unigram XML format, false otherwise */ public static boolean isXmlUnigramDictionary(final String filename) { - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(new File(filename))); + try (final BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(filename), "UTF-8"))) { final String firstLine = reader.readLine(); return firstLine.matches("^\\s*<wordlist .*>\\s*$"); - } catch (FileNotFoundException e) { + } catch (final IOException e) { return false; - } catch (IOException e) { - return false; - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - // do nothing - } - } } } @@ -300,8 +284,8 @@ public class XmlDictInputOutput { * @param bigrams the file to read the bigrams from, or null. * @return the in-memory representation of the dictionary. */ - public static FusionDictionary readDictionaryXml(final InputStream unigrams, - final InputStream shortcuts, final InputStream bigrams) + public static FusionDictionary readDictionaryXml(final BufferedInputStream unigrams, + final BufferedInputStream shortcuts, final BufferedInputStream bigrams) throws SAXException, IOException, ParserConfigurationException { final SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); @@ -350,8 +334,8 @@ public class XmlDictInputOutput { * @param destination a destination stream to write to. * @param dict the dictionary to write. */ - public static void writeDictionaryXml(Writer destination, FusionDictionary dict) - throws IOException { + public static void writeDictionaryXml(final BufferedWriter destination, + final FusionDictionary dict) throws IOException { final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<>(); for (WordProperty wordProperty : dict) { wordPropertiesInDict.add(wordProperty); diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java index fccb654b0..0236a446d 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java @@ -62,13 +62,13 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { final File dst = File.createTempFile("testGetRawDict", ".tmp"); dst.deleteOnExit(); - - final OutputStream out = Compress.getCompressedStream( + try (final OutputStream out = Compress.getCompressedStream( Compress.getCompressedStream( Compress.getCompressedStream( - new BufferedOutputStream(new FileOutputStream(dst))))); - final DictEncoder dictEncoder = new Ver2DictEncoder(out); - dictEncoder.writeDictionary(dict, new FormatOptions(2, false)); + new BufferedOutputStream(new FileOutputStream(dst)))))) { + final DictEncoder dictEncoder = new Ver2DictEncoder(out); + dictEncoder.writeDictionary(dict, new FormatOptions(2, false)); + } // Test for an actually compressed dictionary and its contents final BinaryDictOffdeviceUtils.DecoderChainSpec decodeSpec = @@ -96,11 +96,11 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { // Randomly create some 4k file containing garbage final File dst = File.createTempFile("testGetRawDict", ".tmp"); dst.deleteOnExit(); - final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst)); - for (int i = 0; i < 1024; ++i) { - out.write(0x12345678); + try (final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst))) { + for (int i = 0; i < 1024; ++i) { + out.write(0x12345678); + } } - out.close(); // Test that a random data file actually fails assertNull("Wrongly identified data file", @@ -108,12 +108,12 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { final File gzDst = File.createTempFile("testGetRawDict", ".tmp"); gzDst.deleteOnExit(); - final OutputStream gzOut = - Compress.getCompressedStream(new BufferedOutputStream(new FileOutputStream(gzDst))); - for (int i = 0; i < 1024; ++i) { - gzOut.write(0x12345678); + try (final OutputStream gzOut = Compress.getCompressedStream( + new BufferedOutputStream(new FileOutputStream(gzDst)))) { + for (int i = 0; i < 1024; ++i) { + gzOut.write(0x12345678); + } } - gzOut.close(); // Test that a compressed random data file actually fails assertNull("Wrongly identified data file", |