1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #error This test requires brlapi.
11 #include "base/bind.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
14 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
15 #include "chrome/browser/chromeos/login/lock/screen_locker_tester.h"
16 #include "chrome/browser/chromeos/profiles/profile_helper.h"
17 #include "chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h"
18 #include "chrome/browser/extensions/api/braille_display_private/braille_display_private_api.h"
19 #include "chrome/browser/extensions/api/braille_display_private/brlapi_connection.h"
20 #include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
21 #include "chrome/browser/extensions/extension_apitest.h"
22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/test/base/testing_profile.h"
24 #include "chromeos/chromeos_switches.h"
25 #include "components/user_manager/user_manager.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/test/test_utils.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 using chromeos::ProfileHelper;
32 using chromeos::ScreenLocker;
33 using user_manager::UserManager;
34 using chromeos::test::ScreenLockerTester;
35 using content::BrowserThread;
37 namespace extensions {
39 namespace braille_display_private {
43 const char kTestUserName[] = "owner@invalid.domain";
45 // Used to make ReadKeys return an error.
46 brlapi_keyCode_t kErrorKeyCode = BRLAPI_KEY_MAX;
50 // Data maintained by the mock BrlapiConnection. This data lives throughout
51 // a test, while the api implementation takes ownership of the connection
53 struct MockBrlapiConnectionData {
57 std::vector<std::string> written_content;
58 // List of brlapi key codes. A negative number makes the connection mock
59 // return an error from ReadKey.
60 std::deque<brlapi_keyCode_t> pending_keys;
61 // Causes a new display to appear to appear on disconnect, that is the
62 // display size doubles and the controller gets notified of a brltty
64 bool reappear_on_disconnect;
67 class MockBrlapiConnection : public BrlapiConnection {
69 explicit MockBrlapiConnection(MockBrlapiConnectionData* data)
71 virtual ConnectResult Connect(const OnDataReadyCallback& on_data_ready)
73 data_->connected = true;
74 on_data_ready_ = on_data_ready;
75 if (!data_->pending_keys.empty()) {
76 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
77 base::Bind(&MockBrlapiConnection::NotifyDataReady,
78 base::Unretained(this)));
80 return CONNECT_SUCCESS;
83 virtual void Disconnect() override {
84 data_->connected = false;
85 if (data_->reappear_on_disconnect) {
86 data_->display_size *= 2;
87 BrowserThread::PostTask(
88 BrowserThread::IO, FROM_HERE,
89 base::Bind(&BrailleControllerImpl::PokeSocketDirForTesting,
90 base::Unretained(BrailleControllerImpl::GetInstance())));
94 virtual bool Connected() override {
95 return data_->connected;
98 virtual brlapi_error_t* BrlapiError() override {
102 virtual std::string BrlapiStrError() override {
103 return data_->error.brlerrno != BRLAPI_ERROR_SUCCESS ? "Error" : "Success";
106 virtual bool GetDisplaySize(size_t* size) override {
107 *size = data_->display_size;
111 virtual bool WriteDots(const unsigned char* cells) override {
112 std::string written(reinterpret_cast<const char*>(cells),
113 data_->display_size);
114 data_->written_content.push_back(written);
118 virtual int ReadKey(brlapi_keyCode_t* key_code) override {
119 if (!data_->pending_keys.empty()) {
120 brlapi_keyCode_t queued_key_code = data_->pending_keys.front();
121 data_->pending_keys.pop_front();
122 if (queued_key_code == kErrorKeyCode) {
123 data_->error.brlerrno = BRLAPI_ERROR_EOF;
124 return -1; // Signal error.
126 *key_code = queued_key_code;
135 void NotifyDataReady() {
136 on_data_ready_.Run();
137 if (!data_->pending_keys.empty()) {
138 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
139 base::Bind(&MockBrlapiConnection::NotifyDataReady,
140 base::Unretained(this)));
144 MockBrlapiConnectionData* data_;
145 OnDataReadyCallback on_data_ready_;
148 class BrailleDisplayPrivateApiTest : public ExtensionApiTest {
150 virtual void SetUpInProcessBrowserTestFixture() override {
151 ExtensionApiTest::SetUpInProcessBrowserTestFixture();
152 connection_data_.connected = false;
153 connection_data_.display_size = 0;
154 connection_data_.error.brlerrno = BRLAPI_ERROR_SUCCESS;
155 connection_data_.reappear_on_disconnect = false;
156 BrailleControllerImpl::GetInstance()->SetCreateBrlapiConnectionForTesting(
158 &BrailleDisplayPrivateApiTest::CreateBrlapiConnection,
159 base::Unretained(this)));
160 DisableAccessibilityManagerBraille();
164 MockBrlapiConnectionData connection_data_;
166 // By default, don't let the accessibility manager interfere and
167 // steal events. Some tests override this to keep the normal behaviour
168 // of the accessibility manager.
169 virtual void DisableAccessibilityManagerBraille() {
170 chromeos::AccessibilityManager::SetBrailleControllerForTest(
171 &stub_braille_controller_);
175 scoped_ptr<BrlapiConnection> CreateBrlapiConnection() {
176 return scoped_ptr<BrlapiConnection>(
177 new MockBrlapiConnection(&connection_data_));
180 StubBrailleController stub_braille_controller_;
183 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, WriteDots) {
184 connection_data_.display_size = 11;
185 ASSERT_TRUE(RunComponentExtensionTest("braille_display_private/write_dots"))
187 ASSERT_EQ(3U, connection_data_.written_content.size());
188 const std::string expected_content(connection_data_.display_size, '\0');
189 for (size_t i = 0; i < connection_data_.written_content.size(); ++i) {
190 ASSERT_EQ(std::string(
191 connection_data_.display_size,
192 static_cast<char>(i)),
193 connection_data_.written_content[i])
194 << "String " << i << " doesn't match";
198 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, KeyEvents) {
199 connection_data_.display_size = 11;
201 // Braille navigation commands.
202 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
203 BRLAPI_KEY_CMD_LNUP);
204 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
205 BRLAPI_KEY_CMD_LNDN);
206 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
207 BRLAPI_KEY_CMD_FWINLT);
208 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
209 BRLAPI_KEY_CMD_FWINRT);
210 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
212 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
214 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
215 BRLAPI_KEY_CMD_ROUTE | 5);
217 // Braille display standard keyboard emulation.
219 // An ascii character.
220 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_SYM | 'A');
221 // A non-ascii 'latin1' character. Small letter a with ring above.
222 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_SYM | 0xE5);
223 // A non-latin1 Unicode character. LATIN SMALL LETTER A WITH MACRON.
224 connection_data_.pending_keys.push_back(
225 BRLAPI_KEY_TYPE_SYM | BRLAPI_KEY_SYM_UNICODE | 0x100);
226 // A Unicode character outside the BMP. CAT FACE WITH TEARS OF JOY.
227 // With anticipation for the first emoji-enabled braille display.
228 connection_data_.pending_keys.push_back(
229 BRLAPI_KEY_TYPE_SYM | BRLAPI_KEY_SYM_UNICODE | 0x1F639);
230 // Invalid Unicode character.
231 connection_data_.pending_keys.push_back(
232 BRLAPI_KEY_TYPE_SYM | BRLAPI_KEY_SYM_UNICODE | 0x110000);
234 // Non-alphanumeric function keys.
237 connection_data_.pending_keys.push_back(
238 BRLAPI_KEY_TYPE_SYM | BRLAPI_KEY_SYM_BACKSPACE);
240 connection_data_.pending_keys.push_back(
241 BRLAPI_KEY_TYPE_SYM | BRLAPI_KEY_FLG_SHIFT | BRLAPI_KEY_SYM_TAB);
242 // Alt+F3. (0-based).
243 connection_data_.pending_keys.push_back(
244 BRLAPI_KEY_TYPE_SYM | BRLAPI_KEY_FLG_META |
245 (BRLAPI_KEY_SYM_FUNCTION + 2));
248 connection_data_.pending_keys.push_back(
249 BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_FLG_CONTROL | BRLAPI_KEY_CMD_PASSDOTS |
250 BRLAPI_DOT1 | BRLAPI_DOT2);
252 // Braille dot keys, all combinations including space (0).
253 for (int i = 0; i < 256; ++i) {
254 connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD |
255 BRLAPI_KEY_CMD_PASSDOTS | i);
258 ASSERT_TRUE(RunComponentExtensionTest("braille_display_private/key_events"));
261 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, DisplayStateChanges) {
262 connection_data_.display_size = 11;
263 connection_data_.pending_keys.push_back(kErrorKeyCode);
264 connection_data_.reappear_on_disconnect = true;
265 ASSERT_TRUE(RunComponentExtensionTest(
266 "braille_display_private/display_state_changes"));
269 class BrailleDisplayPrivateAPIUserTest : public BrailleDisplayPrivateApiTest {
271 virtual void SetUpCommandLine(CommandLine* command_line) override {
272 command_line->AppendSwitch(chromeos::switches::kLoginManager);
273 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile,
274 TestingProfile::kTestUserProfileDir);
277 class MockEventDelegate : public BrailleDisplayPrivateAPI::EventDelegate {
279 MockEventDelegate() : event_count_(0) {}
281 int GetEventCount() { return event_count_; }
283 virtual void BroadcastEvent(scoped_ptr<Event> event) override {
286 virtual bool HasListener() override { return true; }
292 MockEventDelegate* SetMockEventDelegate(BrailleDisplayPrivateAPI* api) {
293 MockEventDelegate* delegate = new MockEventDelegate();
294 api->SetEventDelegateForTest(
295 scoped_ptr<BrailleDisplayPrivateAPI::EventDelegate>(delegate).Pass());
299 void LockScreen(ScreenLockerTester* tester) {
300 ScreenLocker::Show();
301 tester->EmulateWindowManagerReady();
302 content::WindowedNotificationObserver lock_state_observer(
303 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
304 content::NotificationService::AllSources());
305 if (!tester->IsLocked())
306 lock_state_observer.Wait();
307 ASSERT_TRUE(tester->IsLocked());
310 void DismissLockScreen(ScreenLockerTester* tester) {
311 ScreenLocker::Hide();
312 content::WindowedNotificationObserver lock_state_observer(
313 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
314 content::NotificationService::AllSources());
315 if (tester->IsLocked())
316 lock_state_observer.Wait();
317 ASSERT_FALSE(tester->IsLocked());
321 virtual void DisableAccessibilityManagerBraille() override {
322 // Let the accessibility manager behave as usual for these tests.
326 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateAPIUserTest,
327 KeyEventOnLockScreen) {
328 scoped_ptr<ScreenLockerTester> tester(ScreenLocker::GetTester());
330 user_manager::UserManager::Get()->UserLoggedIn(
331 kTestUserName, kTestUserName, true);
332 user_manager::UserManager::Get()->SessionStarted();
333 Profile* profile = ProfileManager::GetActiveUserProfile();
335 ProfileHelper::GetSigninProfile()->IsSameProfile(profile))
336 << ProfileHelper::GetSigninProfile()->GetDebugName() << " vs. "
337 << profile->GetDebugName();
339 // Create API and event delegate for sign in profile.
340 BrailleDisplayPrivateAPI signin_api(ProfileHelper::GetSigninProfile());
341 MockEventDelegate* signin_delegate = SetMockEventDelegate(&signin_api);
342 EXPECT_EQ(0, signin_delegate->GetEventCount());
343 // Create api and delegate for the logged in user.
344 BrailleDisplayPrivateAPI user_api(profile);
345 MockEventDelegate* user_delegate = SetMockEventDelegate(&user_api);
347 // Send key event to both profiles.
349 key_event.command = KEY_COMMAND_LINE_UP;
350 signin_api.OnBrailleKeyEvent(key_event);
351 user_api.OnBrailleKeyEvent(key_event);
352 EXPECT_EQ(0, signin_delegate->GetEventCount());
353 EXPECT_EQ(1, user_delegate->GetEventCount());
355 // Lock screen, and make sure that the key event goes to the
357 LockScreen(tester.get());
358 signin_api.OnBrailleKeyEvent(key_event);
359 user_api.OnBrailleKeyEvent(key_event);
360 EXPECT_EQ(1, signin_delegate->GetEventCount());
361 EXPECT_EQ(1, user_delegate->GetEventCount());
363 // Unlock screen, making sur ekey events go to the user profile again.
364 DismissLockScreen(tester.get());
365 signin_api.OnBrailleKeyEvent(key_event);
366 user_api.OnBrailleKeyEvent(key_event);
367 EXPECT_EQ(1, signin_delegate->GetEventCount());
368 EXPECT_EQ(2, user_delegate->GetEventCount());
371 } // namespace braille_display_private
373 } // namespace extensions