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 ConnectResult
Connect(const OnDataReadyCallback
& on_data_ready
) override
{
72 data_
->connected
= true;
73 on_data_ready_
= on_data_ready
;
74 if (!data_
->pending_keys
.empty()) {
75 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
76 base::Bind(&MockBrlapiConnection::NotifyDataReady
,
77 base::Unretained(this)));
79 return CONNECT_SUCCESS
;
82 void Disconnect() override
{
83 data_
->connected
= false;
84 if (data_
->reappear_on_disconnect
) {
85 data_
->display_size
*= 2;
86 BrowserThread::PostTask(
87 BrowserThread::IO
, FROM_HERE
,
88 base::Bind(&BrailleControllerImpl::PokeSocketDirForTesting
,
89 base::Unretained(BrailleControllerImpl::GetInstance())));
93 bool Connected() override
{ return data_
->connected
; }
95 brlapi_error_t
* BrlapiError() override
{ return &data_
->error
; }
97 std::string
BrlapiStrError() override
{
98 return data_
->error
.brlerrno
!= BRLAPI_ERROR_SUCCESS
? "Error" : "Success";
101 bool GetDisplaySize(size_t* size
) override
{
102 *size
= data_
->display_size
;
106 bool WriteDots(const unsigned char* cells
) override
{
107 std::string
written(reinterpret_cast<const char*>(cells
),
108 data_
->display_size
);
109 data_
->written_content
.push_back(written
);
113 int ReadKey(brlapi_keyCode_t
* key_code
) override
{
114 if (!data_
->pending_keys
.empty()) {
115 brlapi_keyCode_t queued_key_code
= data_
->pending_keys
.front();
116 data_
->pending_keys
.pop_front();
117 if (queued_key_code
== kErrorKeyCode
) {
118 data_
->error
.brlerrno
= BRLAPI_ERROR_EOF
;
119 return -1; // Signal error.
121 *key_code
= queued_key_code
;
130 void NotifyDataReady() {
131 on_data_ready_
.Run();
132 if (!data_
->pending_keys
.empty()) {
133 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
134 base::Bind(&MockBrlapiConnection::NotifyDataReady
,
135 base::Unretained(this)));
139 MockBrlapiConnectionData
* data_
;
140 OnDataReadyCallback on_data_ready_
;
143 class BrailleDisplayPrivateApiTest
: public ExtensionApiTest
{
145 void SetUpInProcessBrowserTestFixture() override
{
146 ExtensionApiTest::SetUpInProcessBrowserTestFixture();
147 connection_data_
.connected
= false;
148 connection_data_
.display_size
= 0;
149 connection_data_
.error
.brlerrno
= BRLAPI_ERROR_SUCCESS
;
150 connection_data_
.reappear_on_disconnect
= false;
151 BrailleControllerImpl::GetInstance()->SetCreateBrlapiConnectionForTesting(
153 &BrailleDisplayPrivateApiTest::CreateBrlapiConnection
,
154 base::Unretained(this)));
155 DisableAccessibilityManagerBraille();
159 MockBrlapiConnectionData connection_data_
;
161 // By default, don't let the accessibility manager interfere and
162 // steal events. Some tests override this to keep the normal behaviour
163 // of the accessibility manager.
164 virtual void DisableAccessibilityManagerBraille() {
165 chromeos::AccessibilityManager::SetBrailleControllerForTest(
166 &stub_braille_controller_
);
170 scoped_ptr
<BrlapiConnection
> CreateBrlapiConnection() {
171 return scoped_ptr
<BrlapiConnection
>(
172 new MockBrlapiConnection(&connection_data_
));
175 StubBrailleController stub_braille_controller_
;
178 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest
, WriteDots
) {
179 connection_data_
.display_size
= 11;
180 ASSERT_TRUE(RunComponentExtensionTest("braille_display_private/write_dots"))
182 ASSERT_EQ(3U, connection_data_
.written_content
.size());
183 const std::string
expected_content(connection_data_
.display_size
, '\0');
184 for (size_t i
= 0; i
< connection_data_
.written_content
.size(); ++i
) {
185 ASSERT_EQ(std::string(
186 connection_data_
.display_size
,
187 static_cast<char>(i
)),
188 connection_data_
.written_content
[i
])
189 << "String " << i
<< " doesn't match";
193 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest
, KeyEvents
) {
194 connection_data_
.display_size
= 11;
196 // Braille navigation commands.
197 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
198 BRLAPI_KEY_CMD_LNUP
);
199 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
200 BRLAPI_KEY_CMD_LNDN
);
201 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
202 BRLAPI_KEY_CMD_FWINLT
);
203 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
204 BRLAPI_KEY_CMD_FWINRT
);
205 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
207 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
209 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
210 BRLAPI_KEY_CMD_ROUTE
| 5);
212 // Braille display standard keyboard emulation.
214 // An ascii character.
215 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_SYM
| 'A');
216 // A non-ascii 'latin1' character. Small letter a with ring above.
217 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_SYM
| 0xE5);
218 // A non-latin1 Unicode character. LATIN SMALL LETTER A WITH MACRON.
219 connection_data_
.pending_keys
.push_back(
220 BRLAPI_KEY_TYPE_SYM
| BRLAPI_KEY_SYM_UNICODE
| 0x100);
221 // A Unicode character outside the BMP. CAT FACE WITH TEARS OF JOY.
222 // With anticipation for the first emoji-enabled braille display.
223 connection_data_
.pending_keys
.push_back(
224 BRLAPI_KEY_TYPE_SYM
| BRLAPI_KEY_SYM_UNICODE
| 0x1F639);
225 // Invalid Unicode character.
226 connection_data_
.pending_keys
.push_back(
227 BRLAPI_KEY_TYPE_SYM
| BRLAPI_KEY_SYM_UNICODE
| 0x110000);
229 // Non-alphanumeric function keys.
232 connection_data_
.pending_keys
.push_back(
233 BRLAPI_KEY_TYPE_SYM
| BRLAPI_KEY_SYM_BACKSPACE
);
235 connection_data_
.pending_keys
.push_back(
236 BRLAPI_KEY_TYPE_SYM
| BRLAPI_KEY_FLG_SHIFT
| BRLAPI_KEY_SYM_TAB
);
237 // Alt+F3. (0-based).
238 connection_data_
.pending_keys
.push_back(
239 BRLAPI_KEY_TYPE_SYM
| BRLAPI_KEY_FLG_META
|
240 (BRLAPI_KEY_SYM_FUNCTION
+ 2));
243 connection_data_
.pending_keys
.push_back(
244 BRLAPI_KEY_TYPE_CMD
| BRLAPI_KEY_FLG_CONTROL
| BRLAPI_KEY_CMD_PASSDOTS
|
245 BRLAPI_DOT1
| BRLAPI_DOT2
);
247 // Braille dot keys, all combinations including space (0).
248 for (int i
= 0; i
< 256; ++i
) {
249 connection_data_
.pending_keys
.push_back(BRLAPI_KEY_TYPE_CMD
|
250 BRLAPI_KEY_CMD_PASSDOTS
| i
);
253 ASSERT_TRUE(RunComponentExtensionTest("braille_display_private/key_events"));
256 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest
, DisplayStateChanges
) {
257 connection_data_
.display_size
= 11;
258 connection_data_
.pending_keys
.push_back(kErrorKeyCode
);
259 connection_data_
.reappear_on_disconnect
= true;
260 ASSERT_TRUE(RunComponentExtensionTest(
261 "braille_display_private/display_state_changes"));
264 class BrailleDisplayPrivateAPIUserTest
: public BrailleDisplayPrivateApiTest
{
266 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
267 command_line
->AppendSwitch(chromeos::switches::kLoginManager
);
268 command_line
->AppendSwitchASCII(chromeos::switches::kLoginProfile
,
269 TestingProfile::kTestUserProfileDir
);
272 class MockEventDelegate
: public BrailleDisplayPrivateAPI::EventDelegate
{
274 MockEventDelegate() : event_count_(0) {}
276 int GetEventCount() { return event_count_
; }
278 void BroadcastEvent(scoped_ptr
<Event
> event
) override
{ ++event_count_
; }
279 bool HasListener() override
{ return true; }
285 MockEventDelegate
* SetMockEventDelegate(BrailleDisplayPrivateAPI
* api
) {
286 MockEventDelegate
* delegate
= new MockEventDelegate();
287 api
->SetEventDelegateForTest(
288 scoped_ptr
<BrailleDisplayPrivateAPI::EventDelegate
>(delegate
).Pass());
292 void LockScreen(ScreenLockerTester
* tester
) {
293 ScreenLocker::Show();
294 tester
->EmulateWindowManagerReady();
295 content::WindowedNotificationObserver
lock_state_observer(
296 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED
,
297 content::NotificationService::AllSources());
298 if (!tester
->IsLocked())
299 lock_state_observer
.Wait();
300 ASSERT_TRUE(tester
->IsLocked());
303 void DismissLockScreen(ScreenLockerTester
* tester
) {
304 ScreenLocker::Hide();
305 content::WindowedNotificationObserver
lock_state_observer(
306 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED
,
307 content::NotificationService::AllSources());
308 if (tester
->IsLocked())
309 lock_state_observer
.Wait();
310 ASSERT_FALSE(tester
->IsLocked());
314 void DisableAccessibilityManagerBraille() override
{
315 // Let the accessibility manager behave as usual for these tests.
319 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateAPIUserTest
,
320 KeyEventOnLockScreen
) {
321 scoped_ptr
<ScreenLockerTester
> tester(ScreenLocker::GetTester());
323 user_manager::UserManager::Get()->UserLoggedIn(
324 kTestUserName
, kTestUserName
, true);
325 user_manager::UserManager::Get()->SessionStarted();
326 Profile
* profile
= ProfileManager::GetActiveUserProfile();
328 ProfileHelper::GetSigninProfile()->IsSameProfile(profile
))
329 << ProfileHelper::GetSigninProfile()->GetDebugName() << " vs. "
330 << profile
->GetDebugName();
332 // Create API and event delegate for sign in profile.
333 BrailleDisplayPrivateAPI
signin_api(ProfileHelper::GetSigninProfile());
334 MockEventDelegate
* signin_delegate
= SetMockEventDelegate(&signin_api
);
335 EXPECT_EQ(0, signin_delegate
->GetEventCount());
336 // Create api and delegate for the logged in user.
337 BrailleDisplayPrivateAPI
user_api(profile
);
338 MockEventDelegate
* user_delegate
= SetMockEventDelegate(&user_api
);
340 // Send key event to both profiles.
342 key_event
.command
= KEY_COMMAND_LINE_UP
;
343 signin_api
.OnBrailleKeyEvent(key_event
);
344 user_api
.OnBrailleKeyEvent(key_event
);
345 EXPECT_EQ(0, signin_delegate
->GetEventCount());
346 EXPECT_EQ(1, user_delegate
->GetEventCount());
348 // Lock screen, and make sure that the key event goes to the
350 LockScreen(tester
.get());
351 signin_api
.OnBrailleKeyEvent(key_event
);
352 user_api
.OnBrailleKeyEvent(key_event
);
353 EXPECT_EQ(1, signin_delegate
->GetEventCount());
354 EXPECT_EQ(1, user_delegate
->GetEventCount());
356 // Unlock screen, making sur ekey events go to the user profile again.
357 DismissLockScreen(tester
.get());
358 signin_api
.OnBrailleKeyEvent(key_event
);
359 user_api
.OnBrailleKeyEvent(key_event
);
360 EXPECT_EQ(1, signin_delegate
->GetEventCount());
361 EXPECT_EQ(2, user_delegate
->GetEventCount());
364 } // namespace braille_display_private
366 } // namespace extensions