Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / easy_unlock_private / easy_unlock_private_api.cc
1 // Copyright 2014 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.
4
5 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h"
6
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_bluetooth_util.h"
12 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
15 #include "chrome/browser/signin/easy_unlock_service.h"
16 #include "chrome/common/extensions/api/easy_unlock_private.h"
17 #include "extensions/browser/browser_context_keyed_api_factory.h"
18 #include "grit/generated_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20
21 #if defined(OS_CHROMEOS)
22 #include "chrome/browser/chromeos/chromeos_utils.h"
23 #include "components/user_manager/user.h"
24 #include "components/user_manager/user_manager.h"
25 #endif
26
27 namespace extensions {
28 namespace api {
29
30 namespace {
31
32 static base::LazyInstance<BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI> >
33     g_factory = LAZY_INSTANCE_INITIALIZER;
34
35 // Utility method for getting the API's crypto delegate.
36 EasyUnlockPrivateCryptoDelegate* GetCryptoDelegate(
37     content::BrowserContext* context) {
38   return BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>::Get(context)
39              ->crypto_delegate();
40 }
41
42 EasyUnlockScreenlockStateHandler* GetScreenlockStateHandler(
43     content::BrowserContext* context) {
44   return EasyUnlockService::Get(Profile::FromBrowserContext(context))
45       ->GetScreenlockStateHandler();
46 }
47
48 EasyUnlockScreenlockStateHandler::State ToScreenlockStateHandlerState(
49     easy_unlock_private::State state) {
50   switch (state) {
51     case easy_unlock_private::STATE_NO_BLUETOOTH:
52       return EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH;
53     case easy_unlock_private::STATE_BLUETOOTH_CONNECTING:
54       return EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING;
55     case easy_unlock_private::STATE_NO_PHONE:
56       return EasyUnlockScreenlockStateHandler::STATE_NO_PHONE;
57     case easy_unlock_private::STATE_PHONE_NOT_AUTHENTICATED:
58       return EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED;
59     case easy_unlock_private::STATE_PHONE_LOCKED:
60       return EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED;
61     case easy_unlock_private::STATE_PHONE_UNLOCKABLE:
62       return EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE;
63     case easy_unlock_private::STATE_PHONE_NOT_NEARBY:
64       return EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY;
65     case easy_unlock_private::STATE_PHONE_UNSUPPORTED:
66       return EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED;
67     case easy_unlock_private::STATE_AUTHENTICATED:
68       return EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED;
69     default:
70       return EasyUnlockScreenlockStateHandler::STATE_INACTIVE;
71   }
72 }
73
74 }  // namespace
75
76 // static
77 BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>*
78     EasyUnlockPrivateAPI::GetFactoryInstance() {
79   return g_factory.Pointer();
80 }
81
82 EasyUnlockPrivateAPI::EasyUnlockPrivateAPI(content::BrowserContext* context)
83     : crypto_delegate_(EasyUnlockPrivateCryptoDelegate::Create()) {
84 }
85
86 EasyUnlockPrivateAPI::~EasyUnlockPrivateAPI() {}
87
88 EasyUnlockPrivateGetStringsFunction::EasyUnlockPrivateGetStringsFunction() {
89 }
90 EasyUnlockPrivateGetStringsFunction::~EasyUnlockPrivateGetStringsFunction() {
91 }
92
93 bool EasyUnlockPrivateGetStringsFunction::RunSync() {
94   scoped_ptr<base::DictionaryValue> strings(new base::DictionaryValue);
95
96 #if defined(OS_CHROMEOS)
97   const base::string16 device_type = chromeos::GetChromeDeviceType();
98 #else
99   // TODO(isherman): Set an appropriate device name for non-ChromeOS devices.
100   const base::string16 device_type = base::ASCIIToUTF16("Chromeschnozzle");
101 #endif  // defined(OS_CHROMEOS)
102
103 #if defined(OS_CHROMEOS)
104   const user_manager::UserManager* manager = user_manager::UserManager::Get();
105   const user_manager::User* user = manager ? manager->GetActiveUser() : NULL;
106   const std::string user_email_utf8 =
107       user ? user->display_email() : std::string();
108   const base::string16 user_email = base::UTF8ToUTF16(user_email_utf8);
109 #else
110   // TODO(isherman): Set an appropriate user display email for non-ChromeOS
111   // platforms.
112   const base::string16 user_email = base::UTF8ToUTF16("superman@example.com");
113 #endif  // defined(OS_CHROMEOS)
114
115   // Common strings.
116   strings->SetString(
117       "learnMoreLinkTitle",
118       l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_LEARN_MORE_LINK_TITLE));
119
120   // Setup notification strings.
121   strings->SetString(
122       "setupNotificationTitle",
123       l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_TITLE,
124                                  device_type));
125   strings->SetString(
126       "setupNotificationMessage",
127       l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_MESSAGE,
128                                  device_type));
129   strings->SetString(
130       "setupNotificationButtonTitle",
131       l10n_util::GetStringUTF16(
132           IDS_EASY_UNLOCK_SETUP_NOTIFICATION_BUTTON_TITLE));
133
134   // Success notification strings.
135   strings->SetString(
136       "successNotificationTitle",
137       l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SUCCESS_NOTIFICATION_TITLE));
138   strings->SetString(
139       "successNotificationMessage",
140       l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SUCCESS_NOTIFICATION_MESSAGE,
141                                  device_type));
142
143   // Chromebook added to Easy Unlock notification strings.
144   strings->SetString(
145       "chromebookAddedNotificationTitle",
146       l10n_util::GetStringUTF16(
147           IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_TITLE));
148   strings->SetString(
149      "chromebookAddedNotificationMessage",
150      l10n_util::GetStringFUTF16(
151           IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_MESSAGE,
152           device_type));
153
154   // Setup dialog strings.
155   // Step 1: Intro.
156   strings->SetString(
157       "setupIntroHeaderTitle",
158       l10n_util::GetStringFUTF16(
159           IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TITLE, device_type));
160   strings->SetString(
161       "setupIntroHeaderText",
162       l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TEXT,
163                                  device_type,
164                                  user_email));
165   strings->SetString(
166       "setupIntroFindPhoneButtonLabel",
167       l10n_util::GetStringUTF16(
168           IDS_EASY_UNLOCK_SETUP_INTRO_FIND_PHONE_BUTTON_LABEL));
169   strings->SetString(
170       "setupIntroFindingPhoneButtonLabel",
171       l10n_util::GetStringUTF16(
172           IDS_EASY_UNLOCK_SETUP_INTRO_FINDING_PHONE_BUTTON_LABEL));
173   strings->SetString(
174       "setupIntroRetryFindPhoneButtonLabel",
175       l10n_util::GetStringUTF16(
176           IDS_EASY_UNLOCK_SETUP_INTRO_RETRY_FIND_PHONE_BUTTON_LABEL));
177   strings->SetString(
178       "setupIntroHowIsThisSecureLinkText",
179       l10n_util::GetStringUTF16(
180           IDS_EASY_UNLOCK_SETUP_INTRO_HOW_IS_THIS_SECURE_LINK_TEXT));
181   // Step 2: Found a viable phone.
182   strings->SetString(
183       "setupFoundPhoneHeaderTitle",
184       l10n_util::GetStringFUTF16(
185           IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TITLE, device_type));
186   strings->SetString(
187       "setupFoundPhoneHeaderText",
188       l10n_util::GetStringFUTF16(
189           IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TEXT, device_type));
190   strings->SetString(
191       "setupFoundPhoneUseThisPhoneButtonLabel",
192       l10n_util::GetStringUTF16(
193           IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_USE_THIS_PHONE_BUTTON_LABEL));
194   strings->SetString(
195       "setupPairingPhoneFailedButtonLabel",
196       l10n_util::GetStringUTF16(
197           IDS_EASY_UNLOCK_SETUP_PAIRING_PHONE_FAILED_BUTTON_LABEL));
198   // Step 3: Setup completed successfully.
199   strings->SetString(
200       "setupCompleteHeaderTitle",
201       l10n_util::GetStringUTF16(
202           IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TITLE));
203   strings->SetString(
204       "setupCompleteHeaderText",
205       l10n_util::GetStringUTF16(
206           IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TEXT));
207   strings->SetString(
208       "setupCompleteTryItOutButtonLabel",
209       l10n_util::GetStringUTF16(
210           IDS_EASY_UNLOCK_SETUP_COMPLETE_TRY_IT_OUT_BUTTON_LABEL));
211   strings->SetString(
212       "setupCompleteSettingsLinkText",
213       l10n_util::GetStringUTF16(
214           IDS_EASY_UNLOCK_SETUP_COMPLETE_SETTINGS_LINK_TEXT));
215
216   // Error strings.
217   strings->SetString(
218       "setupErrorBluetoothUnavailable",
219       l10n_util::GetStringFUTF16(
220           IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_UNAVAILBLE, device_type));
221   strings->SetString(
222       "setupErrorOffline",
223       l10n_util::GetStringFUTF16(
224           IDS_EASY_UNLOCK_SETUP_ERROR_OFFLINE, device_type));
225   strings->SetString(
226       "setupErrorFindingPhone",
227       l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SETUP_ERROR_FINDING_PHONE));
228   strings->SetString(
229       "setupErrorBluetoothConnectionFailed",
230       l10n_util::GetStringFUTF16(
231           IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_CONNECTION_FAILED,
232           device_type));
233   strings->SetString(
234       "setupErrorConnectionToPhoneTimeout",
235        l10n_util::GetStringFUTF16(
236            IDS_EASY_UNLOCK_SETUP_ERROR_CONNECT_TO_PHONE_TIMEOUT,
237            device_type));
238   strings->SetString(
239       "setupErrorSyncPhoneState",
240        l10n_util::GetStringUTF16(
241            IDS_EASY_UNLOCK_SETUP_ERROR_SYNC_PHONE_STATE_FAILED));
242   strings->SetString(
243       "setupErrorConnectingToPhone",
244       l10n_util::GetStringFUTF16(
245           IDS_EASY_UNLOCK_SETUP_ERROR_CONNECTING_TO_PHONE, device_type));
246
247   // TODO(isherman): Remove this string once the app has been updated.
248   strings->SetString("setupIntroHeaderFootnote", base::string16());
249
250   SetResult(strings.release());
251   return true;
252 }
253
254 EasyUnlockPrivatePerformECDHKeyAgreementFunction::
255 EasyUnlockPrivatePerformECDHKeyAgreementFunction() {}
256
257 EasyUnlockPrivatePerformECDHKeyAgreementFunction::
258 ~EasyUnlockPrivatePerformECDHKeyAgreementFunction() {}
259
260 bool EasyUnlockPrivatePerformECDHKeyAgreementFunction::RunAsync() {
261   scoped_ptr<easy_unlock_private::PerformECDHKeyAgreement::Params> params =
262       easy_unlock_private::PerformECDHKeyAgreement::Params::Create(*args_);
263   EXTENSION_FUNCTION_VALIDATE(params);
264
265   GetCryptoDelegate(browser_context())->PerformECDHKeyAgreement(
266       params->private_key,
267       params->public_key,
268       base::Bind(&EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData,
269                  this));
270   return true;
271 }
272
273 void EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData(
274     const std::string& secret_key) {
275   // TODO(tbarzic): Improve error handling.
276   if (!secret_key.empty()) {
277     results_ = easy_unlock_private::PerformECDHKeyAgreement::Results::Create(
278         secret_key);
279   }
280   SendResponse(true);
281 }
282
283 EasyUnlockPrivateGenerateEcP256KeyPairFunction::
284 EasyUnlockPrivateGenerateEcP256KeyPairFunction() {}
285
286 EasyUnlockPrivateGenerateEcP256KeyPairFunction::
287 ~EasyUnlockPrivateGenerateEcP256KeyPairFunction() {}
288
289 bool EasyUnlockPrivateGenerateEcP256KeyPairFunction::RunAsync() {
290   GetCryptoDelegate(browser_context())->GenerateEcP256KeyPair(
291       base::Bind(&EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData,
292                  this));
293   return true;
294 }
295
296 void EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData(
297     const std::string& private_key,
298     const std::string& public_key) {
299   // TODO(tbarzic): Improve error handling.
300   if (!public_key.empty() && !private_key.empty()) {
301     results_ = easy_unlock_private::GenerateEcP256KeyPair::Results::Create(
302         public_key, private_key);
303   }
304   SendResponse(true);
305 }
306
307 EasyUnlockPrivateCreateSecureMessageFunction::
308 EasyUnlockPrivateCreateSecureMessageFunction() {}
309
310 EasyUnlockPrivateCreateSecureMessageFunction::
311 ~EasyUnlockPrivateCreateSecureMessageFunction() {}
312
313 bool EasyUnlockPrivateCreateSecureMessageFunction::RunAsync() {
314   scoped_ptr<easy_unlock_private::CreateSecureMessage::Params> params =
315       easy_unlock_private::CreateSecureMessage::Params::Create(*args_);
316   EXTENSION_FUNCTION_VALIDATE(params);
317
318   GetCryptoDelegate(browser_context())->CreateSecureMessage(
319       params->payload,
320       params->key,
321       params->options.associated_data ?
322           *params->options.associated_data : std::string(),
323       params->options.public_metadata ?
324           *params->options.public_metadata : std::string(),
325       params->options.verification_key_id ?
326           *params->options.verification_key_id : std::string(),
327       params->options.encrypt_type,
328       params->options.sign_type,
329       base::Bind(&EasyUnlockPrivateCreateSecureMessageFunction::OnData,
330                  this));
331   return true;
332 }
333
334 void EasyUnlockPrivateCreateSecureMessageFunction::OnData(
335     const std::string& message) {
336   // TODO(tbarzic): Improve error handling.
337   if (!message.empty()) {
338     results_ = easy_unlock_private::CreateSecureMessage::Results::Create(
339         message);
340   }
341   SendResponse(true);
342 }
343
344 EasyUnlockPrivateUnwrapSecureMessageFunction::
345 EasyUnlockPrivateUnwrapSecureMessageFunction() {}
346
347 EasyUnlockPrivateUnwrapSecureMessageFunction::
348 ~EasyUnlockPrivateUnwrapSecureMessageFunction() {}
349
350 bool EasyUnlockPrivateUnwrapSecureMessageFunction::RunAsync() {
351   scoped_ptr<easy_unlock_private::UnwrapSecureMessage::Params> params =
352       easy_unlock_private::UnwrapSecureMessage::Params::Create(*args_);
353   EXTENSION_FUNCTION_VALIDATE(params);
354
355   GetCryptoDelegate(browser_context())->UnwrapSecureMessage(
356       params->secure_message,
357       params->key,
358       params->options.associated_data ?
359           *params->options.associated_data : std::string(),
360       params->options.encrypt_type,
361       params->options.sign_type,
362       base::Bind(&EasyUnlockPrivateUnwrapSecureMessageFunction::OnData,
363                  this));
364   return true;
365 }
366
367 void EasyUnlockPrivateUnwrapSecureMessageFunction::OnData(
368     const std::string& data) {
369   // TODO(tbarzic): Improve error handling.
370   if (!data.empty())
371     results_ = easy_unlock_private::UnwrapSecureMessage::Results::Create(data);
372   SendResponse(true);
373 }
374
375 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::
376     EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {}
377
378 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::
379     ~EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {}
380
381 bool EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::RunAsync() {
382   scoped_ptr<easy_unlock_private::SeekBluetoothDeviceByAddress::Params> params(
383       easy_unlock_private::SeekBluetoothDeviceByAddress::Params::Create(
384           *args_));
385   EXTENSION_FUNCTION_VALIDATE(params.get());
386
387   easy_unlock::SeekBluetoothDeviceByAddress(
388       params->device_address,
389       base::Bind(
390           &EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::
391               OnSeekCompleted,
392           this));
393   return true;
394 }
395
396 void EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekCompleted(
397     const easy_unlock::SeekDeviceResult& seek_result) {
398   if (seek_result.success) {
399     SendResponse(true);
400   } else {
401     SetError(seek_result.error_message);
402     SendResponse(false);
403   }
404 }
405
406 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
407     EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
408
409 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
410     ~EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
411
412 void EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
413     ConnectToService(device::BluetoothDevice* device,
414                      const device::BluetoothUUID& uuid) {
415   easy_unlock::ConnectToBluetoothServiceInsecurely(
416       device,
417       uuid,
418       base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
419                      OnConnect,
420                  this),
421       base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
422                      OnConnectError,
423                  this));
424 }
425
426 EasyUnlockPrivateUpdateScreenlockStateFunction::
427     EasyUnlockPrivateUpdateScreenlockStateFunction() {}
428
429 EasyUnlockPrivateUpdateScreenlockStateFunction::
430     ~EasyUnlockPrivateUpdateScreenlockStateFunction() {}
431
432 bool EasyUnlockPrivateUpdateScreenlockStateFunction::RunSync() {
433   scoped_ptr<easy_unlock_private::UpdateScreenlockState::Params> params(
434       easy_unlock_private::UpdateScreenlockState::Params::Create(*args_));
435   EXTENSION_FUNCTION_VALIDATE(params.get());
436
437   EasyUnlockScreenlockStateHandler* screenlock_state_handler =
438       GetScreenlockStateHandler(browser_context());
439   if (screenlock_state_handler) {
440     screenlock_state_handler->ChangeState(
441         ToScreenlockStateHandlerState(params->state));
442     return true;
443   }
444
445   SetError("Not allowed");
446   return false;
447 }
448
449 EasyUnlockPrivateSetPermitAccessFunction::
450     EasyUnlockPrivateSetPermitAccessFunction() {
451 }
452
453 EasyUnlockPrivateSetPermitAccessFunction::
454     ~EasyUnlockPrivateSetPermitAccessFunction() {
455 }
456
457 bool EasyUnlockPrivateSetPermitAccessFunction::RunSync() {
458   scoped_ptr<easy_unlock_private::SetPermitAccess::Params> params(
459       easy_unlock_private::SetPermitAccess::Params::Create(*args_));
460   EXTENSION_FUNCTION_VALIDATE(params.get());
461
462   Profile* profile = Profile::FromBrowserContext(browser_context());
463   EasyUnlockService::Get(profile)
464       ->SetPermitAccess(*params->permit_access.ToValue());
465
466   return true;
467 }
468
469 EasyUnlockPrivateGetPermitAccessFunction::
470     EasyUnlockPrivateGetPermitAccessFunction() {
471 }
472
473 EasyUnlockPrivateGetPermitAccessFunction::
474     ~EasyUnlockPrivateGetPermitAccessFunction() {
475 }
476
477 bool EasyUnlockPrivateGetPermitAccessFunction::RunSync() {
478   Profile* profile = Profile::FromBrowserContext(browser_context());
479   const base::DictionaryValue* permit_value =
480       EasyUnlockService::Get(profile)->GetPermitAccess();
481   if (permit_value) {
482     scoped_ptr<easy_unlock_private::PermitRecord> permit =
483         easy_unlock_private::PermitRecord::FromValue(*permit_value);
484     results_ = easy_unlock_private::GetPermitAccess::Results::Create(*permit);
485   }
486
487   return true;
488 }
489
490 EasyUnlockPrivateClearPermitAccessFunction::
491     EasyUnlockPrivateClearPermitAccessFunction() {
492 }
493
494 EasyUnlockPrivateClearPermitAccessFunction::
495     ~EasyUnlockPrivateClearPermitAccessFunction() {
496 }
497
498 bool EasyUnlockPrivateClearPermitAccessFunction::RunSync() {
499   Profile* profile = Profile::FromBrowserContext(browser_context());
500   EasyUnlockService::Get(profile)->ClearPermitAccess();
501   return true;
502 }
503
504 EasyUnlockPrivateSetRemoteDevicesFunction::
505     EasyUnlockPrivateSetRemoteDevicesFunction() {
506 }
507
508 EasyUnlockPrivateSetRemoteDevicesFunction::
509     ~EasyUnlockPrivateSetRemoteDevicesFunction() {
510 }
511
512 bool EasyUnlockPrivateSetRemoteDevicesFunction::RunSync() {
513   scoped_ptr<easy_unlock_private::SetRemoteDevices::Params> params(
514       easy_unlock_private::SetRemoteDevices::Params::Create(*args_));
515   EXTENSION_FUNCTION_VALIDATE(params.get());
516
517   Profile* profile = Profile::FromBrowserContext(browser_context());
518   if (params->devices.empty()) {
519     EasyUnlockService::Get(profile)->ClearRemoteDevices();
520   } else {
521     base::ListValue devices;
522     for (size_t i = 0; i < params->devices.size(); ++i) {
523       devices.Append(params->devices[i]->ToValue().release());
524     }
525     EasyUnlockService::Get(profile)->SetRemoteDevices(devices);
526   }
527
528   return true;
529 }
530
531 EasyUnlockPrivateGetRemoteDevicesFunction::
532     EasyUnlockPrivateGetRemoteDevicesFunction() {
533 }
534
535 EasyUnlockPrivateGetRemoteDevicesFunction::
536     ~EasyUnlockPrivateGetRemoteDevicesFunction() {
537 }
538
539 bool EasyUnlockPrivateGetRemoteDevicesFunction::RunSync() {
540   Profile* profile = Profile::FromBrowserContext(browser_context());
541   const base::ListValue* devices =
542       EasyUnlockService::Get(profile)->GetRemoteDevices();
543   SetResult(devices ? devices->DeepCopy() : new base::ListValue());
544   return true;
545 }
546
547 }  // namespace api
548 }  // namespace extensions