1// Copyright (c) 2012 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/automation/testing_automation_provider.h"
6
7#include "ash/shell.h"
8#include "ash/shell_delegate.h"
9#include "ash/system/tray/system_tray_delegate.h"
10#include "base/command_line.h"
11#include "base/i18n/time_formatting.h"
12#include "base/prefs/pref_service.h"
13#include "base/strings/stringprintf.h"
14#include "base/strings/utf_string_conversions.h"
15#include "base/time/time.h"
16#include "chrome/browser/automation/automation_provider_json.h"
17#include "chrome/browser/automation/automation_provider_observers.h"
18#include "chrome/browser/automation/automation_util.h"
19#include "chrome/browser/browser_process.h"
20#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
21#include "chrome/browser/chromeos/accessibility/accessibility_util.h"
22#include "chrome/browser/chromeos/cros/network_library.h"
23#include "chrome/browser/chromeos/login/default_user_images.h"
24#include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
25#include "chrome/browser/chromeos/login/existing_user_controller.h"
26#include "chrome/browser/chromeos/login/login_display.h"
27#include "chrome/browser/chromeos/login/login_display_host_impl.h"
28#include "chrome/browser/chromeos/login/screen_locker.h"
29#include "chrome/browser/chromeos/login/screens/eula_screen.h"
30#include "chrome/browser/chromeos/login/screens/network_screen.h"
31#include "chrome/browser/chromeos/login/screens/update_screen.h"
32#include "chrome/browser/chromeos/login/screens/user_image_screen.h"
33#include "chrome/browser/chromeos/login/startup_utils.h"
34#include "chrome/browser/chromeos/login/webui_login_display.h"
35#include "chrome/browser/chromeos/login/wizard_controller.h"
36#include "chrome/browser/chromeos/net/proxy_config_handler.h"
37#include "chrome/browser/chromeos/settings/cros_settings.h"
38#include "chrome/browser/chromeos/settings/cros_settings_names.h"
39#include "chrome/browser/chromeos/system/timezone_settings.h"
40#include "chrome/browser/prefs/proxy_config_dictionary.h"
41#include "chrome/browser/ui/browser.h"
42#include "chrome/browser/ui/browser_window.h"
43#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
44#include "chrome/common/pref_names.h"
45#include "chromeos/audio/cras_audio_handler.h"
46#include "chromeos/dbus/dbus_thread_manager.h"
47#include "chromeos/dbus/session_manager_client.h"
48#include "chromeos/dbus/update_engine_client.h"
49#include "chromeos/network/network_state_handler.h"
50#include "chromeos/network/onc/onc_utils.h"
51#include "content/public/browser/web_contents.h"
52#include "net/base/network_change_notifier.h"
53#include "policy/policy_constants.h"
54#include "ui/views/widget/widget.h"
55
56using chromeos::DBusThreadManager;
57using chromeos::ExistingUserController;
58using chromeos::NetworkLibrary;
59using chromeos::UpdateEngineClient;
60using chromeos::User;
61using chromeos::UserManager;
62using chromeos::WizardController;
63
64namespace {
65
66DictionaryValue* GetNetworkInfoDict(const chromeos::Network* network) {
67  DictionaryValue* item = new DictionaryValue;
68  item->SetString("name", network->name());
69  item->SetString("device_path", network->device_path());
70  item->SetString("status", network->GetStateString());
71  return item;
72}
73
74DictionaryValue* GetWifiInfoDict(const chromeos::WifiNetwork* wifi) {
75  DictionaryValue* item = GetNetworkInfoDict(wifi);
76  item->SetInteger("strength", wifi->strength());
77  item->SetBoolean("encrypted", wifi->encrypted());
78  item->SetString("encryption", wifi->GetEncryptionString());
79  return item;
80}
81
82const char* UpdateStatusToString(
83    UpdateEngineClient::UpdateStatusOperation status) {
84  switch (status) {
85    case UpdateEngineClient::UPDATE_STATUS_IDLE:
86      return "idle";
87    case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE:
88      return "checking for update";
89    case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
90      return "update available";
91    case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
92      return "downloading";
93    case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
94      return "verifying";
95    case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
96      return "finalizing";
97    case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
98      return "updated need reboot";
99    case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT:
100      return "reporting error event";
101    default:
102      return "unknown";
103  }
104}
105
106void UpdateCheckCallback(AutomationJSONReply* reply,
107                         UpdateEngineClient::UpdateCheckResult result) {
108  if (result == UpdateEngineClient::UPDATE_RESULT_SUCCESS)
109    reply->SendSuccess(NULL);
110  else
111    reply->SendError("update check failed");
112  delete reply;
113}
114
115const std::string VPNProviderTypeToString(
116    chromeos::ProviderType provider_type) {
117  switch (provider_type) {
118    case chromeos::PROVIDER_TYPE_L2TP_IPSEC_PSK:
119      return std::string("L2TP_IPSEC_PSK");
120    case chromeos::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT:
121      return std::string("L2TP_IPSEC_USER_CERT");
122    case chromeos::PROVIDER_TYPE_OPEN_VPN:
123      return std::string("OPEN_VPN");
124    default:
125      return std::string("UNSUPPORTED_PROVIDER_TYPE");
126  }
127}
128
129}  // namespace
130
131#if defined(OS_CHROMEOS)
132void TestingAutomationProvider::PowerChanged(
133    const power_manager::PowerSupplyProperties& proto) {
134  power_supply_properties_ = proto;
135}
136#endif
137
138void TestingAutomationProvider::AcceptOOBENetworkScreen(
139    DictionaryValue* args,
140    IPC::Message* reply_message) {
141  WizardController* wizard_controller = WizardController::default_controller();
142  if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
143          WizardController::kNetworkScreenName) {
144    AutomationJSONReply(this, reply_message).SendError(
145        "Network screen not active.");
146    return;
147  }
148  // Observer will delete itself.
149  new WizardControllerObserver(wizard_controller, this, reply_message);
150  wizard_controller->GetNetworkScreen()->OnContinuePressed();
151}
152
153void TestingAutomationProvider::AcceptOOBEEula(DictionaryValue* args,
154                                               IPC::Message* reply_message) {
155  bool accepted;
156  bool usage_stats_reporting;
157  if (!args->GetBoolean("accepted", &accepted) ||
158      !args->GetBoolean("usage_stats_reporting", &usage_stats_reporting)) {
159    AutomationJSONReply(this, reply_message).SendError(
160        "Invalid or missing args.");
161    return;
162  }
163
164  WizardController* wizard_controller = WizardController::default_controller();
165  if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
166      WizardController::kEulaScreenName) {
167    AutomationJSONReply(this, reply_message).SendError(
168        "EULA screen not active.");
169    return;
170  }
171  // Observer will delete itself.
172  new WizardControllerObserver(wizard_controller, this, reply_message);
173  wizard_controller->GetEulaScreen()->OnExit(accepted, usage_stats_reporting);
174}
175
176void TestingAutomationProvider::CancelOOBEUpdate(DictionaryValue* args,
177                                                 IPC::Message* reply_message) {
178  if (chromeos::StartupUtils::IsOobeCompleted()) {
179    // Update already finished.
180    scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
181    return_value->SetString("next_screen",
182                            WizardController::kLoginScreenName);
183    AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
184    return;
185  }
186  WizardController* wizard_controller = WizardController::default_controller();
187  if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
188          WizardController::kUpdateScreenName) {
189    AutomationJSONReply(this, reply_message).SendError(
190        "Update screen not active.");
191    return;
192  }
193  // Observer will delete itself.
194  new WizardControllerObserver(wizard_controller, this, reply_message);
195  wizard_controller->GetUpdateScreen()->CancelUpdate();
196}
197
198void TestingAutomationProvider::GetLoginInfo(DictionaryValue* args,
199                                             IPC::Message* reply_message) {
200  AutomationJSONReply reply(this, reply_message);
201  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
202
203  const UserManager* user_manager = UserManager::Get();
204  if (!user_manager)
205    reply.SendError("No user manager!");
206  const chromeos::ScreenLocker* screen_locker =
207      chromeos::ScreenLocker::default_screen_locker();
208
209  return_value->SetString("login_ui_type", "webui");
210  return_value->SetBoolean("is_owner", user_manager->IsCurrentUserOwner());
211  return_value->SetBoolean("is_logged_in", user_manager->IsUserLoggedIn());
212  return_value->SetBoolean("is_screen_locked", screen_locker);
213  if (user_manager->IsUserLoggedIn()) {
214    const User* user = user_manager->GetLoggedInUser();
215    return_value->SetBoolean("is_guest", user_manager->IsLoggedInAsGuest());
216    return_value->SetString("email", user->email());
217    return_value->SetString("display_email", user->display_email());
218    switch (user->image_index()) {
219      case User::kExternalImageIndex:
220        return_value->SetString("user_image", "file");
221        break;
222
223      case User::kProfileImageIndex:
224        return_value->SetString("user_image", "profile");
225        break;
226
227      default:
228        return_value->SetInteger("user_image", user->image_index());
229        break;
230    }
231  }
232
233  reply.SendSuccess(return_value.get());
234}
235
236// See the note under LoginAsGuest(). CreateAccount() causes a login as guest.
237void TestingAutomationProvider::ShowCreateAccountUI(
238    DictionaryValue* args, IPC::Message* reply_message) {
239  ExistingUserController* controller =
240      ExistingUserController::current_controller();
241  // Return immediately, since we're going to die before the login is finished.
242  AutomationJSONReply(this, reply_message).SendSuccess(NULL);
243  controller->CreateAccount();
244}
245
246// Logging in as guest will cause session_manager to restart Chrome with new
247// flags. If you used EnableChromeTesting, you will have to call it again.
248void TestingAutomationProvider::LoginAsGuest(DictionaryValue* args,
249                                             IPC::Message* reply_message) {
250  ExistingUserController* controller =
251      ExistingUserController::current_controller();
252  // Return immediately, since we're going to die before the login is finished.
253  AutomationJSONReply(this, reply_message).SendSuccess(NULL);
254  controller->LoginAsGuest();
255}
256
257void TestingAutomationProvider::SubmitLoginForm(DictionaryValue* args,
258                                                IPC::Message* reply_message) {
259  AutomationJSONReply reply(this, reply_message);
260
261  std::string username, password;
262  if (!args->GetString("username", &username) ||
263      !args->GetString("password", &password)) {
264    reply.SendError("Invalid or missing args.");
265    return;
266  }
267
268  chromeos::ExistingUserController* controller =
269      chromeos::ExistingUserController::current_controller();
270  if (!controller) {
271    reply.SendError("Unable to access ExistingUserController");
272    return;
273  }
274
275  // WebUI login.
276  chromeos::WebUILoginDisplay* webui_login_display =
277      static_cast<chromeos::WebUILoginDisplay*>(controller->login_display());
278  VLOG(2) << "TestingAutomationProvider::SubmitLoginForm "
279          << "ShowSigninScreenForCreds(" << username << ", " << password << ")";
280
281  webui_login_display->ShowSigninScreenForCreds(username, password);
282  reply.SendSuccess(NULL);
283}
284
285void TestingAutomationProvider::AddLoginEventObserver(
286    DictionaryValue* args, IPC::Message* reply_message) {
287  ExistingUserController* controller =
288      ExistingUserController::current_controller();
289  AutomationJSONReply reply(this, reply_message);
290  if (!controller) {
291    // This may happen due to SkipToLogin not being called.
292    reply.SendError("Unable to access ExistingUserController");
293    return;
294  }
295
296  if (!automation_event_queue_.get())
297    automation_event_queue_.reset(new AutomationEventQueue);
298
299  int observer_id = automation_event_queue_->AddObserver(
300      new LoginEventObserver(automation_event_queue_.get(), this));
301
302  // Return the observer's id.
303  DictionaryValue return_value;
304  return_value.SetInteger("observer_id", observer_id);
305  reply.SendSuccess(&return_value);
306}
307
308void TestingAutomationProvider::SignOut(DictionaryValue* args,
309                                        IPC::Message* reply_message) {
310  ash::Shell::GetInstance()->system_tray_delegate()->SignOut();
311  // Sign out has the side effect of restarting the session_manager
312  // and chrome, thereby severing the automation channel, so it's
313  // not really necessary to send a reply back. The next line is
314  // for consistency with other methods.
315  AutomationJSONReply(this, reply_message).SendSuccess(NULL);
316}
317
318void TestingAutomationProvider::PickUserImage(DictionaryValue* args,
319                                              IPC::Message* reply_message) {
320  std::string image_type;
321  int image_number = -1;
322  if (!args->GetString("image", &image_type)
323      && !args->GetInteger("image", &image_number)) {
324    AutomationJSONReply(this, reply_message).SendError(
325        "Invalid or missing args.");
326    return;
327  }
328  WizardController* wizard_controller = WizardController::default_controller();
329  if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
330          WizardController::kUserImageScreenName) {
331    AutomationJSONReply(this, reply_message).SendError(
332        "User image screen not active.");
333    return;
334  }
335  chromeos::UserImageScreen* image_screen =
336      wizard_controller->GetUserImageScreen();
337  // Observer will delete itself unless error is returned.
338  WizardControllerObserver* observer =
339      new WizardControllerObserver(wizard_controller, this, reply_message);
340  if (image_type == "profile") {
341    image_screen->OnImageSelected("", image_type);
342    image_screen->OnImageAccepted();
343  } else if (image_type.empty() && image_number >= 0 &&
344             image_number < chromeos::kDefaultImagesCount) {
345    image_screen->OnImageSelected(
346        chromeos::GetDefaultImageUrl(image_number), image_type);
347    image_screen->OnImageAccepted();
348  } else {
349    AutomationJSONReply(this, reply_message).SendError(
350        "Invalid or missing args.");
351    delete observer;
352    return;
353  }
354}
355
356void TestingAutomationProvider::SkipToLogin(DictionaryValue* args,
357                                            IPC::Message* reply_message) {
358  bool skip_post_login_screens;
359  // The argument name is a legacy. If set to |true|, this argument causes any
360  // screens that may otherwise be shown after login (registration, Terms of
361  // Service, user image selection) to be skipped.
362  if (!args->GetBoolean("skip_image_selection", &skip_post_login_screens)) {
363    AutomationJSONReply reply(this, reply_message);
364    reply.SendError("Invalid or missing args.");
365    return;
366  }
367  if (skip_post_login_screens)
368    WizardController::SkipPostLoginScreensForTesting();
369
370  WizardController* wizard_controller = WizardController::default_controller();
371  if (!wizard_controller) {
372    AutomationJSONReply reply(this, reply_message);
373    if (ExistingUserController::current_controller()) {
374      // Already at login screen.
375      scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
376      return_value->SetString("next_screen",
377                              WizardController::kLoginScreenName);
378      reply.SendSuccess(return_value.get());
379    } else {
380      reply.SendError("OOBE not active.");
381    }
382    return;
383  }
384
385  // Observer will delete itself.
386  WizardControllerObserver* observer =
387      new WizardControllerObserver(wizard_controller, this, reply_message);
388  observer->set_screen_to_wait_for(WizardController::kLoginScreenName);
389  wizard_controller->SkipToLoginForTesting();
390}
391
392void TestingAutomationProvider::GetOOBEScreenInfo(DictionaryValue* args,
393                                                  IPC::Message* reply_message) {
394  static const char kScreenNameKey[] = "screen_name";
395  AutomationJSONReply reply(this, reply_message);
396  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
397
398  WizardController* wizard_controller = WizardController::default_controller();
399  if (wizard_controller) {
400    if (wizard_controller->login_screen_started()) {
401      return_value->SetString(kScreenNameKey,
402                              WizardController::kLoginScreenName);
403    } else {
404      return_value->SetString(kScreenNameKey,
405                              wizard_controller->current_screen()->GetName());
406    }
407  } else if (ExistingUserController::current_controller()) {
408    return_value->SetString(kScreenNameKey, WizardController::kLoginScreenName);
409  } else {
410    // Already logged in.
411    reply.SendSuccess(NULL);
412    return;
413  }
414  reply.SendSuccess(return_value.get());
415}
416
417void TestingAutomationProvider::LockScreen(DictionaryValue* args,
418                                           IPC::Message* reply_message) {
419  new ScreenLockUnlockObserver(this, reply_message, true);
420  DBusThreadManager::Get()->GetSessionManagerClient()->RequestLockScreen();
421}
422
423void TestingAutomationProvider::UnlockScreen(DictionaryValue* args,
424                                             IPC::Message* reply_message) {
425  std::string password;
426  if (!args->GetString("password", &password)) {
427    AutomationJSONReply(this, reply_message).SendError(
428        "Invalid or missing args.");
429    return;
430  }
431
432  chromeos::ScreenLocker* screen_locker =
433      chromeos::ScreenLocker::default_screen_locker();
434  if (!screen_locker) {
435    AutomationJSONReply(this, reply_message).SendError(
436        "No default screen locker. Are you sure the screen is locked?");
437    return;
438  }
439
440  new ScreenUnlockObserver(this, reply_message);
441  screen_locker->AuthenticateByPassword(password);
442}
443
444// Signing out could have undesirable side effects: session_manager is
445// killed, so its children, including chrome and the window manager, will
446// also be killed. Anything owned by chronos will probably be killed.
447void TestingAutomationProvider::SignoutInScreenLocker(
448    DictionaryValue* args, IPC::Message* reply_message) {
449  AutomationJSONReply reply(this, reply_message);
450  chromeos::ScreenLocker* screen_locker =
451      chromeos::ScreenLocker::default_screen_locker();
452  if (!screen_locker) {
453    reply.SendError(
454        "No default screen locker. Are you sure the screen is locked?");
455    return;
456  }
457
458  // Send success before stopping session because if we're a child of
459  // session manager then we'll die when the session is stopped.
460  reply.SendSuccess(NULL);
461  screen_locker->Signout();
462}
463
464void TestingAutomationProvider::GetBatteryInfo(DictionaryValue* args,
465                                               IPC::Message* reply_message) {
466  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
467
468  const bool battery_is_present = power_supply_properties_.battery_state() !=
469      power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT;
470  const bool line_power_on = power_supply_properties_.external_power() !=
471      power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
472
473  return_value->SetBoolean("battery_is_present", battery_is_present);
474  return_value->SetBoolean("line_power_on", line_power_on);
475
476  if (battery_is_present) {
477    const bool battery_is_full = power_supply_properties_.battery_state() ==
478        power_manager::PowerSupplyProperties_BatteryState_FULL;
479    return_value->SetBoolean("battery_fully_charged", battery_is_full);
480    return_value->SetDouble("battery_percentage",
481                            power_supply_properties_.battery_percent());
482    if (line_power_on) {
483      int64 time = power_supply_properties_.battery_time_to_full_sec();
484      if (time > 0 || battery_is_full)
485        return_value->SetInteger("battery_seconds_to_full", time);
486    } else {
487      int64 time = power_supply_properties_.battery_time_to_empty_sec();
488      if (time > 0)
489        return_value->SetInteger("battery_seconds_to_empty", time);
490    }
491  }
492
493  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
494}
495
496void TestingAutomationProvider::GetNetworkInfo(DictionaryValue* args,
497                                               IPC::Message* reply_message) {
498  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
499  NetworkLibrary* network_library = NetworkLibrary::Get();
500
501  return_value->SetBoolean("offline_mode",
502                           net::NetworkChangeNotifier::IsOffline());
503
504  // Currently connected networks.
505  if (network_library->ethernet_network())
506    return_value->SetString(
507        "connected_ethernet",
508        network_library->ethernet_network()->service_path());
509  if (network_library->wifi_network())
510    return_value->SetString("connected_wifi",
511                            network_library->wifi_network()->service_path());
512  if (network_library->cellular_network())
513    return_value->SetString(
514        "connected_cellular",
515        network_library->cellular_network()->service_path());
516
517  // Ethernet network.
518  bool ethernet_available = network_library->ethernet_available();
519  bool ethernet_enabled = network_library->ethernet_enabled();
520  return_value->SetBoolean("ethernet_available", ethernet_available);
521  return_value->SetBoolean("ethernet_enabled", ethernet_enabled);
522  if (ethernet_available && ethernet_enabled) {
523    const chromeos::EthernetNetwork* ethernet_network =
524        network_library->ethernet_network();
525    if (ethernet_network) {
526      DictionaryValue* items = new DictionaryValue;
527      DictionaryValue* item = GetNetworkInfoDict(ethernet_network);
528      items->Set(ethernet_network->service_path(), item);
529      items->SetInteger("network_type", chromeos::TYPE_ETHERNET);
530      return_value->Set("ethernet_networks", items);
531    }
532  }
533
534  // Wi-fi networks.
535  bool wifi_available = network_library->wifi_available();
536  bool wifi_enabled = network_library->wifi_enabled();
537  return_value->SetBoolean("wifi_available", wifi_available);
538  return_value->SetBoolean("wifi_enabled", wifi_enabled);
539  if (wifi_available && wifi_enabled) {
540    const chromeos::WifiNetworkVector& wifi_networks =
541        network_library->wifi_networks();
542    DictionaryValue* items = new DictionaryValue;
543    for (chromeos::WifiNetworkVector::const_iterator iter =
544         wifi_networks.begin(); iter != wifi_networks.end(); ++iter) {
545      const chromeos::WifiNetwork* wifi = *iter;
546      DictionaryValue* item = GetWifiInfoDict(wifi);
547      items->Set(wifi->service_path(), item);
548    }
549    items->SetInteger("network_type", chromeos::TYPE_WIFI);
550    return_value->Set("wifi_networks", items);
551  }
552
553  // Cellular networks.
554  bool cellular_available = network_library->cellular_available();
555  bool cellular_enabled = network_library->cellular_enabled();
556  return_value->SetBoolean("cellular_available", cellular_available);
557  return_value->SetBoolean("cellular_enabled", cellular_enabled);
558  if (cellular_available && cellular_enabled) {
559    const chromeos::CellularNetworkVector& cellular_networks =
560        network_library->cellular_networks();
561    DictionaryValue* items = new DictionaryValue;
562    for (size_t i = 0; i < cellular_networks.size(); ++i) {
563      DictionaryValue* item = GetNetworkInfoDict(cellular_networks[i]);
564      item->SetInteger("strength", cellular_networks[i]->strength());
565      item->SetString("operator_name", cellular_networks[i]->operator_name());
566      item->SetString("operator_code", cellular_networks[i]->operator_code());
567      item->SetString("payment_url", cellular_networks[i]->payment_url());
568      item->SetString("usage_url", cellular_networks[i]->usage_url());
569      item->SetString("network_technology",
570                      cellular_networks[i]->GetNetworkTechnologyString());
571      item->SetString("activation_state",
572                      cellular_networks[i]->GetActivationStateString());
573      item->SetString("roaming_state",
574                      cellular_networks[i]->GetRoamingStateString());
575      items->Set(cellular_networks[i]->service_path(), item);
576    }
577    items->SetInteger("network_type", chromeos::TYPE_CELLULAR);
578    return_value->Set("cellular_networks", items);
579  }
580
581  // Remembered Wifi Networks.
582  const chromeos::WifiNetworkVector& remembered_wifi =
583      network_library->remembered_wifi_networks();
584  DictionaryValue* remembered_wifi_items = new DictionaryValue;
585  for (chromeos::WifiNetworkVector::const_iterator iter =
586       remembered_wifi.begin(); iter != remembered_wifi.end();
587       ++iter) {
588      const chromeos::WifiNetwork* wifi = *iter;
589      DictionaryValue* item = GetWifiInfoDict(wifi);
590      remembered_wifi_items->Set(wifi->service_path(), item);
591  }
592  remembered_wifi_items->SetInteger("network_type", chromeos::TYPE_WIFI);
593  return_value->Set("remembered_wifi", remembered_wifi_items);
594
595  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
596}
597
598void TestingAutomationProvider::NetworkScan(DictionaryValue* args,
599                                            IPC::Message* reply_message) {
600  NetworkLibrary* network_library = NetworkLibrary::Get();
601  network_library->RequestNetworkScan();
602
603  // Set up an observer (it will delete itself).
604  new NetworkScanObserver(this, reply_message);
605}
606
607void TestingAutomationProvider::ToggleNetworkDevice(
608    DictionaryValue* args, IPC::Message* reply_message) {
609  AutomationJSONReply reply(this, reply_message);
610  std::string device;
611  bool enable;
612  if (!args->GetString("device", &device) ||
613      !args->GetBoolean("enable", &enable)) {
614    reply.SendError("Invalid or missing args.");
615    return;
616  }
617
618  // Set up an observer (it will delete itself).
619  new ToggleNetworkDeviceObserver(this, reply_message, device, enable);
620
621  NetworkLibrary* network_library = NetworkLibrary::Get();
622  if (device == "ethernet") {
623    network_library->EnableEthernetNetworkDevice(enable);
624  } else if (device == "wifi") {
625    network_library->EnableWifiNetworkDevice(enable);
626  } else if (device == "cellular") {
627    network_library->EnableCellularNetworkDevice(enable);
628  } else {
629    reply.SendError(
630        "Unknown device. Valid devices are ethernet, wifi, cellular.");
631    return;
632  }
633}
634
635void TestingAutomationProvider::SetSharedProxies(
636    DictionaryValue* args,
637    IPC::Message* reply_message) {
638
639  AutomationJSONReply reply(this, reply_message);
640  base::Value* value;
641  if (!args->Get("value", &value)) {
642    reply.SendError("Invalid or missing value argument.");
643    return;
644  }
645  std::string error_message;
646  Profile* profile =
647      automation_util::GetCurrentProfileOnChromeOS(&error_message);
648  if (!profile) {
649    reply.SendError(error_message);
650    return;
651  }
652  PrefService* pref_service = profile->GetPrefs();
653  pref_service->Set(prefs::kUseSharedProxies, *value);
654  reply.SendSuccess(NULL);
655}
656
657void TestingAutomationProvider::SetProxySettings(DictionaryValue* args,
658                                                 IPC::Message* reply_message) {
659  AutomationJSONReply reply(this, reply_message);
660  std::string proxy_config_str;
661  if (!args->GetString("proxy_config", &proxy_config_str)) {
662    reply.SendError("Invalid or missing args.");
663    return;
664  }
665
666  const chromeos::NetworkState* network = chromeos::NetworkHandler::Get()->
667      network_state_handler()->DefaultNetwork();
668  if (!network) {
669    reply.SendError("No network connected.");
670    return;
671  }
672
673  scoped_ptr<base::DictionaryValue> proxy_config_dict(
674      chromeos::onc::ReadDictionaryFromJson(proxy_config_str));
675  ProxyConfigDictionary proxy_config(proxy_config_dict.get());
676  chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config, *network);
677
678  reply.SendSuccess(NULL);
679}
680
681void TestingAutomationProvider::ConnectToCellularNetwork(
682    DictionaryValue* args, IPC::Message* reply_message) {
683  std::string service_path;
684  if (!args->GetString("service_path", &service_path)) {
685    AutomationJSONReply(this, reply_message).SendError(
686        "Invalid or missing args.");
687    return;
688  }
689
690  NetworkLibrary* network_library = NetworkLibrary::Get();
691  chromeos::CellularNetwork* cellular =
692      network_library->FindCellularNetworkByPath(service_path);
693  if (!cellular) {
694    AutomationJSONReply(this, reply_message).SendError(
695        "No network found with specified service path.");
696    return;
697  }
698
699  // Set up an observer (it will delete itself).
700  new ServicePathConnectObserver(this, reply_message, service_path);
701
702  network_library->ConnectToCellularNetwork(cellular);
703  network_library->RequestNetworkScan();
704}
705
706void TestingAutomationProvider::DisconnectFromCellularNetwork(
707    DictionaryValue* args, IPC::Message* reply_message) {
708  NetworkLibrary* network_library = NetworkLibrary::Get();
709  const chromeos::CellularNetwork* cellular =
710        network_library->cellular_network();
711  if (!cellular) {
712    AutomationJSONReply(this, reply_message).SendError(
713        "Not connected to any cellular network.");
714    return;
715  }
716
717  // Set up an observer (it will delete itself).
718  new NetworkDisconnectObserver(this, reply_message, cellular->service_path());
719
720  network_library->DisconnectFromNetwork(cellular);
721}
722
723void TestingAutomationProvider::ConnectToWifiNetwork(
724    DictionaryValue* args, IPC::Message* reply_message) {
725  AutomationJSONReply reply(this, reply_message);
726  std::string service_path, password;
727  bool shared;
728  if (!args->GetString("service_path", &service_path) ||
729      !args->GetString("password", &password) ||
730      !args->GetBoolean("shared", &shared)) {
731    reply.SendError("Invalid or missing args.");
732    return;
733  }
734
735  NetworkLibrary* network_library = NetworkLibrary::Get();
736  chromeos::WifiNetwork* wifi =
737      network_library->FindWifiNetworkByPath(service_path);
738  if (!wifi) {
739    reply.SendError("No network found with specified service path.");
740    return;
741  }
742  if (!password.empty())
743    wifi->SetPassphrase(password);
744
745  // Regardless of what was passed, if the network is open and visible,
746  // the network must be shared because of a UI restriction.
747  if (wifi->encryption() == chromeos::SECURITY_NONE)
748    shared = true;
749
750  // Set up an observer (it will delete itself).
751  new ServicePathConnectObserver(this, reply_message, service_path);
752
753  network_library->ConnectToWifiNetwork(wifi, shared);
754  network_library->RequestNetworkScan();
755}
756
757void TestingAutomationProvider::ForgetWifiNetwork(
758    DictionaryValue* args, IPC::Message* reply_message) {
759  std::string service_path;
760  if (!args->GetString("service_path", &service_path)) {
761    AutomationJSONReply(this, reply_message).SendError(
762        "Invalid or missing args.");
763    return;
764  }
765
766  NetworkLibrary::Get()->ForgetNetwork(service_path);
767  AutomationJSONReply(this, reply_message).SendSuccess(NULL);
768}
769
770void TestingAutomationProvider::ConnectToHiddenWifiNetwork(
771    DictionaryValue* args, IPC::Message* reply_message) {
772  std::string ssid, security, password;
773  bool shared;
774  if (!args->GetString("ssid", &ssid) ||
775      !args->GetString("security", &security) ||
776      !args->GetString("password", &password) ||
777      !args->GetBoolean("shared", &shared)) {
778    AutomationJSONReply(this, reply_message).SendError(
779        "Invalid or missing args.");
780    return;
781  }
782
783  std::map<std::string, chromeos::ConnectionSecurity> connection_security_map;
784  connection_security_map["SECURITY_NONE"] = chromeos::SECURITY_NONE;
785  connection_security_map["SECURITY_WEP"] = chromeos::SECURITY_WEP;
786  connection_security_map["SECURITY_WPA"] = chromeos::SECURITY_WPA;
787  connection_security_map["SECURITY_RSN"] = chromeos::SECURITY_RSN;
788  connection_security_map["SECURITY_8021X"] = chromeos::SECURITY_8021X;
789
790  if (connection_security_map.find(security) == connection_security_map.end()) {
791    AutomationJSONReply(this, reply_message).SendError(
792        "Unknown security type.");
793    return;
794  }
795  chromeos::ConnectionSecurity connection_security =
796      connection_security_map[security];
797
798  NetworkLibrary* network_library = NetworkLibrary::Get();
799
800  // Set up an observer (it will delete itself).
801  new SSIDConnectObserver(this, reply_message, ssid);
802
803  bool save_credentials = false;
804
805  if (connection_security == chromeos::SECURITY_8021X) {
806    chromeos::NetworkLibrary::EAPConfigData config_data;
807    std::string eap_method, eap_auth, eap_identity;
808    if (!args->GetString("eap_method", &eap_method) ||
809        !args->GetString("eap_auth", &eap_auth) ||
810        !args->GetString("eap_identity", &eap_identity) ||
811        !args->GetBoolean("save_credentials", &save_credentials)) {
812      AutomationJSONReply(this, reply_message).SendError(
813          "Invalid or missing EAP args.");
814      return;
815    }
816
817    std::map<std::string, chromeos::EAPMethod> eap_method_map;
818    eap_method_map["EAP_METHOD_NONE"] = chromeos::EAP_METHOD_UNKNOWN;
819    eap_method_map["EAP_METHOD_PEAP"] = chromeos::EAP_METHOD_PEAP;
820    eap_method_map["EAP_METHOD_TLS"] = chromeos::EAP_METHOD_TLS;
821    eap_method_map["EAP_METHOD_TTLS"] = chromeos::EAP_METHOD_TTLS;
822    eap_method_map["EAP_METHOD_LEAP"] = chromeos::EAP_METHOD_LEAP;
823    if (eap_method_map.find(eap_method) == eap_method_map.end()) {
824      AutomationJSONReply(this, reply_message).SendError(
825          "Unknown EAP Method type.");
826      return;
827    }
828    config_data.method = eap_method_map[eap_method];
829
830    std::map<std::string, chromeos::EAPPhase2Auth> eap_auth_map;
831    eap_auth_map["EAP_PHASE_2_AUTH_AUTO"] = chromeos::EAP_PHASE_2_AUTH_AUTO;
832    eap_auth_map["EAP_PHASE_2_AUTH_MD5"] = chromeos::EAP_PHASE_2_AUTH_MD5;
833    eap_auth_map["EAP_PHASE_2_AUTH_MSCHAP"] =
834        chromeos::EAP_PHASE_2_AUTH_MSCHAP;
835    eap_auth_map["EAP_PHASE_2_AUTH_MSCHAPV2"] =
836        chromeos::EAP_PHASE_2_AUTH_MSCHAPV2;
837    eap_auth_map["EAP_PHASE_2_AUTH_PAP"] = chromeos::EAP_PHASE_2_AUTH_PAP;
838    eap_auth_map["EAP_PHASE_2_AUTH_CHAP"] = chromeos::EAP_PHASE_2_AUTH_CHAP;
839    if (eap_auth_map.find(eap_auth) == eap_auth_map.end()) {
840      AutomationJSONReply(this, reply_message).SendError(
841          "Unknown EAP Phase2 Auth type.");
842      return;
843    }
844    config_data.auth = eap_auth_map[eap_auth];
845
846    config_data.identity = eap_identity;
847
848    // TODO(stevenjb): Parse cert values?
849    config_data.use_system_cas = false;
850    config_data.client_cert_pkcs11_id = "";
851
852    network_library->ConnectToUnconfiguredWifiNetwork(
853        ssid, chromeos::SECURITY_8021X, password, &config_data,
854        save_credentials, shared);
855  } else {
856    network_library->ConnectToUnconfiguredWifiNetwork(
857        ssid, connection_security, password, NULL,
858        save_credentials, shared);
859  }
860}
861
862void TestingAutomationProvider::DisconnectFromWifiNetwork(
863    DictionaryValue* args, IPC::Message* reply_message) {
864  AutomationJSONReply reply(this, reply_message);
865  NetworkLibrary* network_library = NetworkLibrary::Get();
866  const chromeos::WifiNetwork* wifi = network_library->wifi_network();
867  if (!wifi) {
868    reply.SendError("Not connected to any wifi network.");
869    return;
870  }
871
872  network_library->DisconnectFromNetwork(wifi);
873  reply.SendSuccess(NULL);
874}
875
876void TestingAutomationProvider::AddPrivateNetwork(
877    DictionaryValue* args, IPC::Message* reply_message) {
878  std::string hostname, service_name, provider_type, key, cert_id, username,
879      password;
880  if (!args->GetString("hostname", &hostname) ||
881      !args->GetString("service_name", &service_name) ||
882      !args->GetString("provider_type", &provider_type) ||
883      !args->GetString("username", &username) ||
884      !args->GetString("password", &password)) {
885    AutomationJSONReply(this, reply_message)
886        .SendError("Invalid or missing args.");
887    return;
888  }
889
890  NetworkLibrary* network_library = NetworkLibrary::Get();
891
892  // Attempt to connect to the VPN based on the provider type.
893  if (provider_type == VPNProviderTypeToString(
894      chromeos::PROVIDER_TYPE_L2TP_IPSEC_PSK)) {
895    if (!args->GetString("key", &key)) {
896      AutomationJSONReply(this, reply_message)
897          .SendError("Missing key arg.");
898      return;
899    }
900    new VirtualConnectObserver(this, reply_message, service_name);
901    // Connect using a pre-shared key.
902    chromeos::NetworkLibrary::VPNConfigData config_data;
903    config_data.psk = key;
904    config_data.username = username;
905    config_data.user_passphrase = password;
906    network_library->ConnectToUnconfiguredVirtualNetwork(
907        service_name,
908        hostname,
909        chromeos::PROVIDER_TYPE_L2TP_IPSEC_PSK,
910        config_data);
911  } else if (provider_type == VPNProviderTypeToString(
912      chromeos::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT)) {
913    if (!args->GetString("cert_id", &cert_id)) {
914      AutomationJSONReply(this, reply_message)
915          .SendError("Missing a certificate arg.");
916      return;
917    }
918    new VirtualConnectObserver(this, reply_message, service_name);
919    // Connect using a user certificate.
920    chromeos::NetworkLibrary::VPNConfigData config_data;
921    config_data.client_cert_pkcs11_id = cert_id;
922    config_data.username = username;
923    config_data.user_passphrase = password;
924    network_library->ConnectToUnconfiguredVirtualNetwork(
925        service_name,
926        hostname,
927        chromeos::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT,
928        config_data);
929  } else if (provider_type == VPNProviderTypeToString(
930      chromeos::PROVIDER_TYPE_OPEN_VPN)) {
931    std::string otp;
932    args->GetString("otp", &otp);
933    // Connect using OPEN_VPN.
934    chromeos::NetworkLibrary::VPNConfigData config_data;
935    config_data.client_cert_pkcs11_id = cert_id;
936    config_data.username = username;
937    config_data.user_passphrase = password;
938    config_data.otp = otp;
939    network_library->ConnectToUnconfiguredVirtualNetwork(
940        service_name,
941        hostname,
942        chromeos::PROVIDER_TYPE_OPEN_VPN,
943        config_data);
944  } else {
945    AutomationJSONReply(this, reply_message)
946        .SendError("Unsupported provider type.");
947    return;
948  }
949}
950
951void TestingAutomationProvider::ConnectToPrivateNetwork(
952    DictionaryValue* args, IPC::Message* reply_message) {
953  AutomationJSONReply reply(this, reply_message);
954  std::string service_path;
955  if (!args->GetString("service_path", &service_path)) {
956    reply.SendError("Invalid or missing args.");
957    return;
958  }
959
960  // Connect to a remembered VPN by its service_path. Valid service_paths
961  // can be found in the dictionary returned by GetPrivateNetworkInfo.
962  NetworkLibrary* network_library = NetworkLibrary::Get();
963  chromeos::VirtualNetwork* network =
964      network_library->FindVirtualNetworkByPath(service_path);
965  if (!network) {
966    reply.SendError(base::StringPrintf("No virtual network found: %s",
967                                       service_path.c_str()));
968    return;
969  }
970  if (network->NeedMoreInfoToConnect()) {
971    reply.SendError("Virtual network is missing info required to connect.");
972    return;
973  };
974
975  // Set up an observer (it will delete itself).
976  new VirtualConnectObserver(this, reply_message, network->name());
977  network_library->ConnectToVirtualNetwork(network);
978}
979
980void TestingAutomationProvider::GetPrivateNetworkInfo(
981    DictionaryValue* args, IPC::Message* reply_message) {
982  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
983  NetworkLibrary* network_library = NetworkLibrary::Get();
984  const chromeos::VirtualNetworkVector& virtual_networks =
985      network_library->virtual_networks();
986
987  // Construct a dictionary of fields describing remembered VPNs. Also list
988  // the currently active VPN, if any.
989  if (network_library->virtual_network())
990    return_value->SetString("connected",
991                            network_library->virtual_network()->service_path());
992  for (chromeos::VirtualNetworkVector::const_iterator iter =
993       virtual_networks.begin(); iter != virtual_networks.end(); ++iter) {
994    const chromeos::VirtualNetwork* virt = *iter;
995    DictionaryValue* item = new DictionaryValue;
996    item->SetString("name", virt->name());
997    item->SetString("provider_type",
998                    VPNProviderTypeToString(virt->provider_type()));
999    item->SetString("hostname", virt->server_hostname());
1000    item->SetString("key", virt->psk_passphrase());
1001    item->SetString("cert_id", virt->client_cert_id());
1002    item->SetString("username", virt->username());
1003    item->SetString("password", virt->user_passphrase());
1004    return_value->Set(virt->service_path(), item);
1005  }
1006
1007  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
1008}
1009
1010void TestingAutomationProvider::DisconnectFromPrivateNetwork(
1011    DictionaryValue* args, IPC::Message* reply_message) {
1012  AutomationJSONReply reply(this, reply_message);
1013  NetworkLibrary* network_library = NetworkLibrary::Get();
1014  const chromeos::VirtualNetwork* virt = network_library->virtual_network();
1015  if (!virt) {
1016    reply.SendError("Not connected to any virtual network.");
1017    return;
1018  }
1019
1020  network_library->DisconnectFromNetwork(virt);
1021  reply.SendSuccess(NULL);
1022}
1023
1024void TestingAutomationProvider::ExecuteJavascriptInOOBEWebUI(
1025    DictionaryValue* args, IPC::Message* reply_message) {
1026  std::string javascript, frame_xpath;
1027  if (!args->GetString("javascript", &javascript)) {
1028    AutomationJSONReply(this, reply_message)
1029        .SendError("'javascript' missing or invalid");
1030    return;
1031  }
1032  if (!args->GetString("frame_xpath", &frame_xpath)) {
1033    AutomationJSONReply(this, reply_message)
1034        .SendError("'frame_xpath' missing or invalid");
1035    return;
1036  }
1037  const UserManager* user_manager = UserManager::Get();
1038  if (!user_manager) {
1039    AutomationJSONReply(this, reply_message).SendError(
1040        "No user manager!");
1041    return;
1042  }
1043  if (user_manager->IsUserLoggedIn()) {
1044    AutomationJSONReply(this, reply_message).SendError(
1045        "User is already logged in.");
1046    return;
1047  }
1048  ExistingUserController* controller =
1049      ExistingUserController::current_controller();
1050  if (!controller) {
1051    AutomationJSONReply(this, reply_message).SendError(
1052        "Unable to access ExistingUserController");
1053    return;
1054  }
1055  chromeos::LoginDisplayHostImpl* webui_host =
1056      static_cast<chromeos::LoginDisplayHostImpl*>(
1057          controller->login_display_host());
1058  content::WebContents* web_contents =
1059      webui_host->GetOobeUI()->web_ui()->GetWebContents();
1060
1061  new DomOperationMessageSender(this, reply_message, true);
1062  ExecuteJavascriptInRenderViewFrame(ASCIIToUTF16(frame_xpath),
1063                                     ASCIIToUTF16(javascript),
1064                                     reply_message,
1065                                     web_contents->GetRenderViewHost());
1066}
1067
1068void TestingAutomationProvider::EnableSpokenFeedback(
1069    DictionaryValue* args, IPC::Message* reply_message) {
1070  AutomationJSONReply reply(this, reply_message);
1071  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1072  bool enabled;
1073  if (!args->GetBoolean("enabled", &enabled)) {
1074    reply.SendError("Invalid or missing args.");
1075    return;
1076  }
1077  chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(
1078      enabled, ash::A11Y_NOTIFICATION_NONE);
1079
1080  reply.SendSuccess(return_value.get());
1081}
1082
1083void TestingAutomationProvider::IsSpokenFeedbackEnabled(
1084    DictionaryValue* args, IPC::Message* reply_message) {
1085  AutomationJSONReply reply(this, reply_message);
1086  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1087  return_value->SetBoolean(
1088      "spoken_feedback",
1089      chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
1090  reply.SendSuccess(return_value.get());
1091}
1092
1093void TestingAutomationProvider::GetTimeInfo(Browser* browser,
1094                                            DictionaryValue* args,
1095                                            IPC::Message* reply_message) {
1096  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1097  base::Time time(base::Time::Now());
1098  bool use_24hour_clock = browser && browser->profile()->GetPrefs()->GetBoolean(
1099      prefs::kUse24HourClock);
1100  base::HourClockType hour_clock_type =
1101      use_24hour_clock ? base::k24HourClock : base::k12HourClock;
1102  string16 display_time = base::TimeFormatTimeOfDayWithHourClockType(
1103      time, hour_clock_type, base::kDropAmPm);
1104  string16 timezone =
1105      chromeos::system::TimezoneSettings::GetInstance()->GetCurrentTimezoneID();
1106  return_value->SetString("display_time", display_time);
1107  return_value->SetString("display_date", base::TimeFormatFriendlyDate(time));
1108  return_value->SetString("timezone", timezone);
1109  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
1110}
1111
1112void TestingAutomationProvider::GetTimeInfo(DictionaryValue* args,
1113                                            IPC::Message* reply_message) {
1114  GetTimeInfo(NULL, args, reply_message);
1115}
1116
1117void TestingAutomationProvider::SetTimezone(DictionaryValue* args,
1118                                            IPC::Message* reply_message) {
1119  AutomationJSONReply reply(this, reply_message);
1120  std::string timezone_id;
1121  if (!args->GetString("timezone", &timezone_id)) {
1122    reply.SendError("Invalid or missing args.");
1123    return;
1124  }
1125  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
1126  settings->SetString(chromeos::kSystemTimezone, timezone_id);
1127  reply.SendSuccess(NULL);
1128}
1129
1130void TestingAutomationProvider::UpdateCheck(
1131    DictionaryValue* args,
1132    IPC::Message* reply_message) {
1133  AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message);
1134  DBusThreadManager::Get()->GetUpdateEngineClient()
1135      ->RequestUpdateCheck(base::Bind(UpdateCheckCallback, reply));
1136}
1137
1138void TestingAutomationProvider::GetVolumeInfo(DictionaryValue* args,
1139                                              IPC::Message* reply_message) {
1140  AutomationJSONReply reply(this, reply_message);
1141  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1142  chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
1143  if (!audio_handler) {
1144    reply.SendError("CrasAudioHandler not initialized.");
1145    return;
1146  }
1147  return_value->SetDouble("volume", audio_handler->GetOutputVolumePercent());
1148  return_value->SetBoolean("is_mute", audio_handler->IsOutputMuted());
1149  reply.SendSuccess(return_value.get());
1150}
1151
1152void TestingAutomationProvider::SetVolume(DictionaryValue* args,
1153                                          IPC::Message* reply_message) {
1154  AutomationJSONReply reply(this, reply_message);
1155  double volume_percent;
1156  if (!args->GetDouble("volume", &volume_percent)) {
1157    reply.SendError("Invalid or missing args.");
1158    return;
1159  }
1160  chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
1161  if (!audio_handler) {
1162    reply.SendError("CrasAudioHandler not initialized.");
1163    return;
1164  }
1165  audio_handler->SetOutputVolumePercent(volume_percent);
1166  reply.SendSuccess(NULL);
1167}
1168
1169void TestingAutomationProvider::SetMute(DictionaryValue* args,
1170                                        IPC::Message* reply_message) {
1171  AutomationJSONReply reply(this, reply_message);
1172  bool mute;
1173  if (!args->GetBoolean("mute", &mute)) {
1174    reply.SendError("Invalid or missing args.");
1175    return;
1176  }
1177  chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
1178  if (!audio_handler) {
1179    reply.SendError("CrasAudioHandler not initialized.");
1180    return;
1181  }
1182  audio_handler->SetOutputMute(mute);
1183  reply.SendSuccess(NULL);
1184}
1185
1186void TestingAutomationProvider::OpenCrosh(DictionaryValue* args,
1187                                          IPC::Message* reply_message) {
1188  new NavigationNotificationObserver(
1189      NULL, this, reply_message, 1, false, true);
1190  ash::Shell::GetInstance()->delegate()->OpenCrosh();
1191}
1192
1193void TestingAutomationProvider::AddChromeosObservers() {
1194  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
1195      AddObserver(this);
1196}
1197
1198void TestingAutomationProvider::RemoveChromeosObservers() {
1199  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
1200      RemoveObserver(this);
1201}
1202