#include "ui/base/accelerators/accelerator.h"
#include <memory>
#include <string_view>
#include "ash/accelerators/accelerator_controller_impl.h"
#include "ash/app_list/test/app_list_test_helper.h"
#include "ash/shell.h"
#include "ash/shell_observer.h"
#include "ash/system/network/network_observer.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "base/run_loop.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "chromeos/ash/components/dbus/shill/shill_clients.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/services/assistant/test_support/scoped_assistant_browser_delegate.h"
#include "ui/aura/window.h"
#include "ui/base/accelerators/test_accelerator_target.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/events/test/event_generator.h"
namespace ash {
namespace {
class TestNetworkObserver : public NetworkObserver {
public:
TestNetworkObserver() = default;
TestNetworkObserver(const TestNetworkObserver&) = delete;
TestNetworkObserver& operator=(const TestNetworkObserver&) = delete;
~TestNetworkObserver() override = default;
void RequestToggleWifi() override {
wifi_enabled_status_ = !wifi_enabled_status_;
}
bool wifi_enabled_status() const { return wifi_enabled_status_; }
private:
bool wifi_enabled_status_ = false;
};
}
class AcceleratorTest : public AshTestBase, public OverviewObserver {
public:
AcceleratorTest() : is_in_overview_mode_(false) {}
AcceleratorTest(const AcceleratorTest&) = delete;
AcceleratorTest& operator=(const AcceleratorTest&) = delete;
void SetUp() override {
AshTestBase::SetUp();
Shell::Get()->overview_controller()->AddObserver(this);
}
void TearDown() override {
Shell::Get()->overview_controller()->RemoveObserver(this);
AshTestBase::TearDown();
}
void SendKeyPressSync(ui::KeyboardCode key,
bool control,
bool shift,
bool alt) {
ui::test::EmulateFullKeyPressReleaseSequence(
GetEventGenerator(), key, control, shift, alt, false);
}
void OnOverviewModeStarting() override { is_in_overview_mode_ = true; }
void OnOverviewModeEnded() override { is_in_overview_mode_ = false; }
protected:
bool is_in_overview_mode_;
};
TEST_F(AcceleratorTest, Basic) {
base::UserActionTester user_action_tester;
EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
SendKeyPressSync(ui::VKEY_VOLUME_MUTE, false, false, false);
EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
SendKeyPressSync(ui::VKEY_VOLUME_DOWN, false, false, false);
EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
SendKeyPressSync(ui::VKEY_VOLUME_UP, false, false, false);
EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
TestNetworkObserver network_observer;
Shell::Get()->system_tray_notifier()->AddNetworkObserver(&network_observer);
EXPECT_FALSE(network_observer.wifi_enabled_status());
SendKeyPressSync(ui::VKEY_WLAN, false, false, false);
EXPECT_TRUE(network_observer.wifi_enabled_status());
SendKeyPressSync(ui::VKEY_WLAN, false, false, false);
EXPECT_FALSE(network_observer.wifi_enabled_status());
Shell::Get()->system_tray_notifier()->RemoveNetworkObserver(
&network_observer);
}
TEST_F(AcceleratorTest, NonRepeatableNeedingWindowActions) {
aura::Window* window_1 =
CreateTestWindowInShell({.bounds = {100, 100}, .window_id = 0});
aura::Window* window_2 =
CreateTestWindowInShell({.bounds = {100, 100}, .window_id = 0});
window_1->Show();
wm::ActivateWindow(window_1);
window_2->Show();
wm::ActivateWindow(window_2);
EXPECT_FALSE(is_in_overview_mode_);
SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, false, false, false);
EXPECT_TRUE(is_in_overview_mode_);
SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, false, false, false);
EXPECT_FALSE(is_in_overview_mode_);
wm::ActivateWindow(window_1);
EXPECT_TRUE(wm::IsActiveWindow(window_1));
EXPECT_FALSE(wm::IsActiveWindow(window_2));
SendKeyPressSync(ui::VKEY_TAB, false, false, true);
EXPECT_TRUE(wm::IsActiveWindow(window_2));
EXPECT_FALSE(wm::IsActiveWindow(window_1));
SendKeyPressSync(ui::VKEY_TAB, false, true, true);
EXPECT_TRUE(wm::IsActiveWindow(window_1));
EXPECT_FALSE(wm::IsActiveWindow(window_2));
WindowState* active_window_state = WindowState::ForActiveWindow();
EXPECT_FALSE(active_window_state->IsFullscreen());
SendKeyPressSync(ui::VKEY_ZOOM, false, false, false);
EXPECT_TRUE(active_window_state->IsFullscreen());
SendKeyPressSync(ui::VKEY_ZOOM, false, false, false);
EXPECT_FALSE(active_window_state->IsFullscreen());
}
TEST_F(AcceleratorTest, ToggleAppList) {
GetAppListTestHelper()->CheckVisibility(false);
SendKeyPressSync(ui::VKEY_LWIN, false, false, false);
base::RunLoop().RunUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
SendKeyPressSync(ui::VKEY_LWIN, false, false, false);
base::RunLoop().RunUntilIdle();
GetAppListTestHelper()->CheckVisibility(false);
}
TEST_F(AcceleratorTest, AssistantKeyWithNewEntryPointEnabled) {
base::UserActionTester user_action_tester;
base::test::TestFuture<void> open_new_entry_point_future;
assistant::ScopedAssistantBrowserDelegate scoped_assistant_browser_delegate;
scoped_assistant_browser_delegate.SetOpenNewEntryPointClosure(
open_new_entry_point_future.GetCallback());
ui::test::EmulateFullKeyPressReleaseSequence(
GetEventGenerator(), ui::VKEY_ASSISTANT,
false, false, false, false);
EXPECT_TRUE(open_new_entry_point_future.Wait());
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Assistant.NewEntryPoint.AssistantKey"));
}
TEST_F(AcceleratorTest, NoSearchPlusAWithNewEntryPointEnabled) {
base::UserActionTester user_action_tester;
base::test::TestFuture<void> open_new_entry_point_future;
assistant::ScopedAssistantBrowserDelegate scoped_assistant_browser_delegate;
scoped_assistant_browser_delegate.SetOpenNewEntryPointClosure(
open_new_entry_point_future.GetCallback());
ui::test::EmulateFullKeyPressReleaseSequence(
GetEventGenerator(), ui::VKEY_A,
false, false, false, true);
task_environment()->RunUntilIdle();
EXPECT_FALSE(open_new_entry_point_future.IsReady())
<< "Search+A shortcut won't be available if new entry point flag is on. "
"New entry point won't be expected to be opened.";
EXPECT_EQ(0, user_action_tester.GetActionCount(
"VoiceInteraction.Started.Search_A"));
}
}