| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/system/ime_menu/ime_menu_tray.h" |
| |
| #include <string_view> |
| |
| #include "ash/accelerators/accelerator_controller_impl.h" |
| #include "ash/accessibility/a11y_feature_type.h" |
| #include "ash/accessibility/accessibility_controller.h" |
| #include "ash/ime/ime_controller_impl.h" |
| #include "ash/ime/test_ime_controller_client.h" |
| #include "ash/public/cpp/ash_view_ids.h" |
| #include "ash/public/cpp/ime_info.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/system/ime_menu/ime_list_view.h" |
| #include "ash/system/status_area_widget.h" |
| #include "ash/system/status_area_widget_test_helper.h" |
| #include "ash/test/ash_test_base.h" |
| #include "base/containers/contains.h" |
| #include "base/run_loop.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/bind.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "components/session_manager/session_manager_types.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/accessibility/ax_enums.mojom.h" |
| #include "ui/accessibility/ax_node_data.h" |
| #include "ui/base/emoji/emoji_panel_helper.h" |
| #include "ui/base/ime/ash/ime_bridge.h" |
| #include "ui/base/ime/text_input_flags.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/display/test/display_manager_test_api.h" |
| #include "ui/events/devices/device_data_manager_test_api.h" |
| #include "ui/events/devices/input_device.h" |
| #include "ui/events/devices/keyboard_device.h" |
| #include "ui/events/devices/touchscreen_device.h" |
| #include "ui/events/event.h" |
| #include "ui/views/accessibility/view_accessibility.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/view_class_properties.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| const int kEmojiButtonId = 1; |
| const int kSettingsButtonId = 2; |
| const int kVoiceButtonId = 3; |
| |
| ImeMenuTray* GetTray() { |
| return StatusAreaWidgetTestHelper::GetStatusAreaWidget()->ime_menu_tray(); |
| } |
| |
| void SetCurrentIme(const std::string& current_ime_id, |
| const std::vector<ImeInfo>& available_imes) { |
| std::vector<ImeInfo> available_ime_ptrs; |
| for (const auto& ime : available_imes) { |
| available_ime_ptrs.push_back(ime); |
| } |
| Shell::Get()->ime_controller()->RefreshIme(current_ime_id, |
| std::move(available_ime_ptrs), |
| std::vector<ImeMenuItem>()); |
| } |
| |
| } // namespace |
| |
| class ImeMenuTrayTest : public AshTestBase { |
| public: |
| ImeMenuTrayTest() = default; |
| ImeMenuTrayTest(const ImeMenuTrayTest&) = delete; |
| ImeMenuTrayTest& operator=(const ImeMenuTrayTest&) = delete; |
| ~ImeMenuTrayTest() override = default; |
| |
| protected: |
| // Returns true if the IME menu tray is visible. |
| bool IsVisible() { return GetTray()->GetVisible(); } |
| |
| // Returns the label text of the tray. |
| std::u16string_view GetTrayText() { return GetTray()->label_->GetText(); } |
| |
| // Returns true if the background color of the tray is active. |
| bool IsTrayBackgroundActive() { return GetTray()->is_active(); } |
| |
| // Returns true if the IME menu bubble has been shown. |
| bool IsBubbleShown() { return GetTray()->GetBubbleView() != nullptr; } |
| |
| // Returns true if emoji palatte is enabled for the current keyboard. |
| bool IsEmojiEnabled() { return GetTray()->is_emoji_enabled_; } |
| |
| // Returns true if handwirting input is enabled for the current keyboard. |
| bool IsHandwritingEnabled() { return GetTray()->is_handwriting_enabled_; } |
| |
| // Returns true if voice input is enabled for the current keyboard. |
| bool IsVoiceEnabled() { return GetTray()->is_voice_enabled_; } |
| |
| views::Button* GetEmojiButton() const { |
| return static_cast<views::Button*>( |
| GetTray()->bubble_->bubble_view()->GetViewByID(kEmojiButtonId)); |
| } |
| |
| views::View* GetSettingsButton() const { |
| auto* bubble = GetTray()->GetBubbleView(); |
| return bubble == nullptr ? nullptr : bubble->GetViewByID(kSettingsButtonId); |
| } |
| |
| views::View* GetVoiceButton() const { |
| return static_cast<views::View*>( |
| GetTray()->bubble_->bubble_view()->GetViewByID(kVoiceButtonId)); |
| } |
| |
| void SetUpKioskSession() { |
| SessionInfo info; |
| info.is_running_in_app_mode = true; |
| info.state = session_manager::SessionState::ACTIVE; |
| Shell::Get()->session_controller()->SetSessionInfo(info); |
| } |
| |
| // Verifies the IME menu list has been updated with the right IME list. |
| void ExpectValidImeList(const std::vector<ImeInfo>& expected_imes, |
| const ImeInfo& expected_current_ime) { |
| const std::map<views::View*, std::string>& ime_map = |
| ImeListViewTestApi(GetTray()->ime_list_view_).ime_map(); |
| EXPECT_EQ(expected_imes.size(), ime_map.size()); |
| |
| std::vector<std::string> expected_ime_ids; |
| for (const auto& ime : expected_imes) { |
| expected_ime_ids.push_back(ime.id); |
| } |
| for (const auto& ime : ime_map) { |
| // Tests that all the IMEs on the view is in the list of selected IMEs. |
| EXPECT_TRUE(base::Contains(expected_ime_ids, ime.second)); |
| |
| // Tests that the checked IME is the current IME. |
| ui::AXNodeData node_data; |
| ime.first->GetViewAccessibility().GetAccessibleNodeData(&node_data); |
| const auto checked_state = static_cast<ax::mojom::CheckedState>( |
| node_data.GetIntAttribute(ax::mojom::IntAttribute::kCheckedState)); |
| if (checked_state == ax::mojom::CheckedState::kTrue) { |
| EXPECT_EQ(expected_current_ime.id, ime.second); |
| } |
| } |
| } |
| |
| // Focuses in the given type of input context. |
| void FocusInInputContext(ui::TextInputType input_type) { |
| IMEBridge::Get()->SetCurrentInputContext( |
| TextInputMethod::InputContext(input_type)); |
| } |
| |
| bool MenuHasOnScreenKeyboardToggle() const { |
| if (!GetTray()->ime_list_view_) { |
| return false; |
| } |
| return ImeListViewTestApi(GetTray()->ime_list_view_).GetToggleView(); |
| } |
| }; |
| |
| // Tests that visibility of IME menu tray should be consistent with the |
| // activation of the IME menu. |
| TEST_F(ImeMenuTrayTest, ImeMenuTrayVisibility) { |
| ASSERT_FALSE(IsVisible()); |
| |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| EXPECT_TRUE(IsVisible()); |
| |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(false); |
| EXPECT_FALSE(IsVisible()); |
| } |
| |
| // Tests that IME menu tray shows the right info of the current IME. |
| TEST_F(ImeMenuTrayTest, TrayLabelTest) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| |
| ImeInfo info1; |
| info1.id = "ime1"; |
| info1.name = u"English"; |
| info1.short_name = u"US"; |
| info1.third_party = false; |
| |
| ImeInfo info2; |
| info2.id = "ime2"; |
| info2.name = u"English UK"; |
| info2.short_name = u"UK"; |
| info2.third_party = true; |
| |
| // Changes the input method to "ime1". |
| SetCurrentIme("ime1", {info1, info2}); |
| EXPECT_EQ(u"US", GetTrayText()); |
| |
| // Changes the input method to a third-party IME extension. |
| SetCurrentIme("ime2", {info1, info2}); |
| EXPECT_EQ(u"UK*", GetTrayText()); |
| } |
| |
| TEST_F(ImeMenuTrayTest, TrayLabelExludesDictation) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| |
| ImeInfo info1; |
| info1.id = "ime1"; |
| info1.name = u"English"; |
| info1.short_name = u"US"; |
| info1.third_party = false; |
| |
| ImeInfo info2; |
| info2.id = "ime2"; |
| info2.name = u"English UK"; |
| info2.short_name = u"UK"; |
| info2.third_party = true; |
| |
| ImeInfo dictation; |
| dictation.id = "_ext_ime_egfdjlfmgnehecnclamagfafdccgfndpdictation"; |
| dictation.name = u"Dictation"; |
| |
| // Changes the input method to "ime1". |
| SetCurrentIme("ime1", {info1, dictation, info2}); |
| EXPECT_EQ(u"US", GetTrayText()); |
| |
| // Changes the input method to a third-party IME extension. |
| SetCurrentIme("ime2", {info1, dictation, info2}); |
| EXPECT_EQ(u"UK*", GetTrayText()); |
| |
| // Sets to "dictation", which shouldn't be shown. |
| SetCurrentIme(dictation.id, {info1, dictation, info2}); |
| EXPECT_EQ(u"", GetTrayText()); |
| } |
| |
| // Tests that the IME menu tray changes background color when tapped, and |
| // tests that the background color becomes 'inactive' when disabling the IME |
| // menu feature. Also makes sure that the shelf won't autohide as long as the |
| // IME menu is open. |
| TEST_F(ImeMenuTrayTest, PerformActionGestureTap) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| ASSERT_FALSE(IsTrayBackgroundActive()); |
| StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); |
| EXPECT_FALSE(status->ShouldShowShelf()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| // Auto-hidden shelf would be forced to be visible as long as the bubble is |
| // open. |
| EXPECT_TRUE(status->ShouldShowShelf()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_FALSE(IsTrayBackgroundActive()); |
| EXPECT_FALSE(IsBubbleShown()); |
| |
| // If disabling the IME menu feature when the menu tray is activated, the tray |
| // element will be deactivated. |
| GestureTapOn(GetTray()); |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(false); |
| EXPECT_FALSE(IsVisible()); |
| EXPECT_FALSE(IsBubbleShown()); |
| EXPECT_FALSE(IsTrayBackgroundActive()); |
| EXPECT_FALSE(status->ShouldShowShelf()); |
| } |
| |
| // Tests that the IME menu reacts to left click. |
| TEST_F(ImeMenuTrayTest, PerformActionLeftClick) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| ASSERT_FALSE(IsTrayBackgroundActive()); |
| |
| LeftClickOn(GetTray()); |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| LeftClickOn(GetTray()); |
| EXPECT_FALSE(IsTrayBackgroundActive()); |
| EXPECT_FALSE(IsBubbleShown()); |
| } |
| |
| // Tests that IME menu list updates when changing the current IME. This should |
| // only happen by using shortcuts (Ctrl + Space / Ctrl + Shift + Space) to |
| // switch IMEs. |
| TEST_F(ImeMenuTrayTest, RefreshImeWithListViewCreated) { |
| GetTray()->SetVisiblePreferred(true); |
| GestureTapOn(GetTray()); |
| |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| ImeInfo info1, info2, info3; |
| info1.id = "ime1"; |
| info1.name = u"English"; |
| info1.short_name = u"US"; |
| info1.third_party = false; |
| |
| info2.id = "ime2"; |
| info2.name = u"English UK"; |
| info2.short_name = u"UK"; |
| info2.third_party = true; |
| |
| info3.id = "ime3"; |
| info3.name = u"Pinyin"; |
| info3.short_name = u"拼"; |
| info3.third_party = false; |
| |
| std::vector<ImeInfo> ime_info_list{info1, info2, info3}; |
| |
| // Switch to ime1. |
| SetCurrentIme("ime1", ime_info_list); |
| EXPECT_EQ(u"US", GetTrayText()); |
| ExpectValidImeList(ime_info_list, info1); |
| |
| // Switch to ime3. |
| SetCurrentIme("ime3", ime_info_list); |
| EXPECT_EQ(u"拼", GetTrayText()); |
| ExpectValidImeList(ime_info_list, info3); |
| |
| // Closes the menu before quitting. |
| GestureTapOn(GetTray()); |
| EXPECT_FALSE(IsTrayBackgroundActive()); |
| EXPECT_FALSE(IsBubbleShown()); |
| } |
| |
| // Tests that quits Chrome with IME menu openned will not crash. |
| TEST_F(ImeMenuTrayTest, QuitChromeWithMenuOpen) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| ASSERT_FALSE(IsTrayBackgroundActive()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| EXPECT_TRUE(IsBubbleShown()); |
| } |
| |
| // Tests using 'Alt+Shift+K' to open the menu. |
| TEST_F(ImeMenuTrayTest, TestAccelerator) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| ASSERT_FALSE(IsTrayBackgroundActive()); |
| |
| Shell::Get()->accelerator_controller()->PerformActionIfEnabled( |
| AcceleratorAction::kToggleImeMenuBubble, {}); |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_FALSE(IsTrayBackgroundActive()); |
| EXPECT_FALSE(IsBubbleShown()); |
| } |
| |
| TEST_F(ImeMenuTrayTest, ShowingEmojiKeysetHidesBubble) { |
| // Setup the callback required by ui::ShowEmojiPanel() to a dummy one. |
| // The ui::ShowEmojiPanel() call in ShowKeyboardWithKeyset will fail |
| // without this callback. |
| ui::SetShowEmojiKeyboardCallback(base::DoNothing()); |
| |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| ASSERT_FALSE(IsTrayBackgroundActive()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| TestImeControllerClient client; |
| Shell::Get()->ime_controller()->SetClient(&client); |
| GetTray()->ShowKeyboardWithKeyset(input_method::ImeKeyset::kEmoji); |
| |
| // The menu should be hidden. |
| EXPECT_FALSE(IsBubbleShown()); |
| } |
| |
| // Tests that the IME menu accelerator toggles the bubble on and off. |
| TEST_F(ImeMenuTrayTest, ImeBubbleAccelerator) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| EXPECT_FALSE(IsBubbleShown()); |
| |
| PressAndReleaseKey(ui::VKEY_K, ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| PressAndReleaseKey(ui::VKEY_K, ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(IsBubbleShown()); |
| } |
| |
| // Tests that tapping the emoji button does not crash. http://crbug.com/739630 |
| TEST_F(ImeMenuTrayTest, TapEmojiButton) { |
| int call_count = 0; |
| ui::SetShowEmojiKeyboardCallback(base::BindLambdaForTesting( |
| [&](ui::EmojiPickerCategory unused, ui::EmojiPickerFocusBehavior, |
| const std::string&) { ++call_count; })); |
| |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| true /* ui enabled */, true /* emoji input enabled */, |
| true /* hanwriting input enabled */, true /* voice input enabled */); |
| |
| // Open the menu. |
| GestureTapOn(GetTray()); |
| |
| // Tap the emoji button. |
| views::Button* emoji_button = GetEmojiButton(); |
| ASSERT_TRUE(emoji_button); |
| GestureTapOn(emoji_button); |
| |
| // The menu should be hidden. |
| EXPECT_FALSE(IsBubbleShown()); |
| |
| // The callback should have been called. |
| EXPECT_EQ(call_count, 1); |
| } |
| |
| TEST_F(ImeMenuTrayTest, ShouldShowBottomButtons) { |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| true /* ui enabled */, true /* emoji input enabled */, |
| true /* hanwriting input enabled */, true /* voice input enabled */); |
| |
| FocusInInputContext(ui::TEXT_INPUT_TYPE_TEXT); |
| GetTray()->ShowBubble(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(GetTray()->AnyBottomButtonShownForTest()); |
| EXPECT_TRUE(IsEmojiEnabled()); |
| EXPECT_TRUE(IsHandwritingEnabled()); |
| EXPECT_TRUE(IsVoiceEnabled()); |
| |
| FocusInInputContext(ui::TEXT_INPUT_TYPE_PASSWORD); |
| |
| GetTray()->CloseBubble(); |
| GetTray()->ShowBubble(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(GetTray()->AnyBottomButtonShownForTest()); |
| EXPECT_FALSE(IsEmojiEnabled()); |
| EXPECT_FALSE(IsHandwritingEnabled()); |
| EXPECT_FALSE(IsVoiceEnabled()); |
| } |
| |
| TEST_F(ImeMenuTrayTest, ShouldShowBottomButtonsSeperate) { |
| FocusInInputContext(ui::TEXT_INPUT_TYPE_TEXT); |
| |
| // Sets emoji disabled. |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| true /* ui enabled */, false /* emoji input disabled */, |
| true /* hanwriting input enabled */, true /* voice input enabled */); |
| |
| GetTray()->ShowBubble(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(GetTray()->AnyBottomButtonShownForTest()); |
| EXPECT_FALSE(IsEmojiEnabled()); |
| EXPECT_TRUE(IsHandwritingEnabled()); |
| EXPECT_TRUE(IsVoiceEnabled()); |
| |
| // Sets emoji enabled, but voice and handwriting disabled. |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| true /* ui enabled */, true /* emoji input enabled */, |
| false /* hanwriting input disabled */, false /* voice input disabled */); |
| |
| GetTray()->CloseBubble(); |
| GetTray()->ShowBubble(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(GetTray()->AnyBottomButtonShownForTest()); |
| EXPECT_TRUE(IsEmojiEnabled()); |
| EXPECT_FALSE(IsHandwritingEnabled()); |
| EXPECT_FALSE(IsVoiceEnabled()); |
| } |
| |
| TEST_F(ImeMenuTrayTest, KioskImeTraySettingsButton) { |
| SetUpKioskSession(); |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| |
| // Open the menu. |
| GestureTapOn(GetTray()); |
| |
| views::View* settings_button = GetSettingsButton(); |
| EXPECT_FALSE(settings_button); |
| } |
| |
| TEST_F(ImeMenuTrayTest, UserSessionImeTraySettingsButton) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| |
| // Open the menu. |
| GestureTapOn(GetTray()); |
| |
| views::View* settings_button = GetSettingsButton(); |
| EXPECT_TRUE(settings_button); |
| } |
| |
| TEST_F(ImeMenuTrayTest, ShowOnScreenKeyboardToggle) { |
| Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); |
| ASSERT_TRUE(IsVisible()); |
| ASSERT_FALSE(IsTrayBackgroundActive()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_TRUE(IsTrayBackgroundActive()); |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| EXPECT_FALSE(MenuHasOnScreenKeyboardToggle()); |
| |
| // The on-screen keyboard toggle should show if the device has a touch |
| // screen, and does not have an internal keyboard. |
| std::vector<ui::TouchscreenDevice> screens; |
| screens.push_back( |
| ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, |
| "Touchscreen", gfx::Size(1024, 768), 0)); |
| ui::DeviceDataManagerTestApi().SetTouchscreenDevices(screens); |
| |
| std::vector<ui::KeyboardDevice> keyboard_devices; |
| keyboard_devices.push_back(ui::KeyboardDevice( |
| 1, ui::InputDeviceType::INPUT_DEVICE_USB, "external keyboard")); |
| ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices); |
| |
| // Bubble gets closed when the keyboard suppression state changes. |
| EXPECT_FALSE(IsBubbleShown()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_TRUE(IsBubbleShown()); |
| |
| EXPECT_TRUE(MenuHasOnScreenKeyboardToggle()); |
| |
| // The toggle should not be removed on IME device refresh. |
| ImeInfo info; |
| info.id = "ime"; |
| info.name = u"English UK"; |
| info.short_name = u"UK"; |
| info.third_party = true; |
| |
| SetCurrentIme("ime", {info}); |
| EXPECT_TRUE(MenuHasOnScreenKeyboardToggle()); |
| |
| // The toggle should be hidden with internal keyboard. |
| keyboard_devices.push_back(ui::KeyboardDevice( |
| 1, ui::InputDeviceType::INPUT_DEVICE_USB, "external keyboard")); |
| keyboard_devices.push_back(ui::KeyboardDevice( |
| 1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "internal keyboard")); |
| ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices); |
| |
| // Bubble gets closed when the keyboard suppression state changes. |
| EXPECT_FALSE(IsBubbleShown()); |
| |
| GestureTapOn(GetTray()); |
| EXPECT_TRUE(IsBubbleShown()); |
| EXPECT_FALSE(MenuHasOnScreenKeyboardToggle()); |
| } |
| |
| TEST_F(ImeMenuTrayTest, ShowVoiceButtonWhenDictationDisabled) { |
| // Enable all extra input options. |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| /*is_extra_input_options_enabled=*/true, |
| /*is_emoji_enabled=*/true, |
| /*is_handwriting_enabled=*/true, /*is_voice_enabled=*/true); |
| |
| // Disable accessibility dictation. |
| Shell::Get() |
| ->accessibility_controller() |
| ->GetFeature(A11yFeatureType::kDictation) |
| .SetEnabled(false); |
| |
| // Show IME tray bubble. |
| GetTray()->ShowBubble(); |
| |
| // Voice button should be shown. |
| views::View* voice_button = GetVoiceButton(); |
| EXPECT_TRUE(voice_button); |
| } |
| |
| TEST_F(ImeMenuTrayTest, HideVoiceButtonWhenDictationEnabled) { |
| // Enable all extra input options. |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| /*is_extra_input_options_enabled=*/true, |
| /*is_emoji_enabled=*/true, |
| /*is_handwriting_enabled=*/true, /*is_voice_enabled=*/true); |
| |
| // Enable accessibility dictation. |
| Shell::Get() |
| ->accessibility_controller() |
| ->GetFeature(A11yFeatureType::kDictation) |
| .SetEnabled(true); |
| |
| // Show IME tray bubble. |
| GetTray()->ShowBubble(); |
| |
| // Voice button should be hidden. |
| views::View* voice_button = GetVoiceButton(); |
| EXPECT_FALSE(voice_button); |
| } |
| |
| TEST_F(ImeMenuTrayTest, ImeMenuHasBottomInsetsOnLockScreen) { |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| true /* ui enabled */, true /* emoji input enabled */, |
| true /* hanwriting input enabled */, true /* voice input enabled */); |
| |
| // SHow IME tray bubble. |
| GetTray()->ShowBubble(); |
| |
| // Make sure there is no margin when the screen is unlocked. |
| gfx::Insets* container_margins = |
| GetTray() |
| ->GetBubbleView() |
| ->GetViewByID(VIEW_ID_IME_LIST_VIEW_SCROLLER) |
| ->GetProperty(views::kMarginsKey); |
| EXPECT_EQ(container_margins->bottom(), 0); |
| |
| BlockUserSession(BLOCKED_BY_LOCK_SCREEN); |
| |
| // Make sure the margin is updated when the screen is locked. |
| GetTray()->ShowBubble(); |
| container_margins = GetTray() |
| ->GetBubbleView() |
| ->GetViewByID(VIEW_ID_IME_LIST_VIEW_SCROLLER) |
| ->GetProperty(views::kMarginsKey); |
| EXPECT_GT(container_margins->bottom(), 0); |
| } |
| |
| TEST_F(ImeMenuTrayTest, AccessibleNames) { |
| Shell::Get()->ime_controller()->SetExtraInputOptionsEnabledState( |
| /*is_extra_input_options_enabled=*/true, /*is_emoji_enabled=*/true, |
| /*is_handwriting_enabled=*/true, /*is_voice_enabled=*/true); |
| |
| { |
| ui::AXNodeData node_data; |
| GetTray()->GetViewAccessibility().GetAccessibleNodeData(&node_data); |
| EXPECT_EQ(node_data.GetString16Attribute(ax::mojom::StringAttribute::kName), |
| l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME)); |
| } |
| |
| // Show IME tray bubble. |
| GetTray()->ShowBubble(); |
| |
| TrayBubbleView* bubble_view = GetTray()->GetBubbleView(); |
| { |
| ui::AXNodeData node_data; |
| bubble_view->GetViewAccessibility().GetAccessibleNodeData(&node_data); |
| EXPECT_EQ(node_data.GetString16Attribute(ax::mojom::StringAttribute::kName), |
| GetTray()->GetAccessibleNameForBubble()); |
| } |
| } |
| |
| } // namespace ash |