Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / automation / testing_automation_provider_chromeos.cc
blobe39d42f1e066fbc2040a964b1ca375fe116c4dbc
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.
5 #include "chrome/browser/automation/testing_automation_provider.h"
7 #include "ash/new_window_delegate.h"
8 #include "ash/shell.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/login/default_user_images.h"
23 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
24 #include "chrome/browser/chromeos/login/existing_user_controller.h"
25 #include "chrome/browser/chromeos/login/login_display.h"
26 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
27 #include "chrome/browser/chromeos/login/screen_locker.h"
28 #include "chrome/browser/chromeos/login/screens/eula_screen.h"
29 #include "chrome/browser/chromeos/login/screens/network_screen.h"
30 #include "chrome/browser/chromeos/login/screens/update_screen.h"
31 #include "chrome/browser/chromeos/login/screens/user_image_screen.h"
32 #include "chrome/browser/chromeos/login/startup_utils.h"
33 #include "chrome/browser/chromeos/login/webui_login_display.h"
34 #include "chrome/browser/chromeos/login/wizard_controller.h"
35 #include "chrome/browser/chromeos/net/proxy_config_handler.h"
36 #include "chrome/browser/chromeos/settings/cros_settings.h"
37 #include "chrome/browser/prefs/proxy_config_dictionary.h"
38 #include "chrome/browser/ui/browser.h"
39 #include "chrome/browser/ui/browser_window.h"
40 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
41 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
42 #include "chrome/common/pref_names.h"
43 #include "chromeos/audio/cras_audio_handler.h"
44 #include "chromeos/dbus/dbus_thread_manager.h"
45 #include "chromeos/dbus/session_manager_client.h"
46 #include "chromeos/dbus/update_engine_client.h"
47 #include "chromeos/settings/cros_settings_names.h"
48 #include "chromeos/settings/timezone_settings.h"
49 #include "content/public/browser/web_contents.h"
50 #include "policy/policy_constants.h"
51 #include "ui/views/widget/widget.h"
53 using chromeos::DBusThreadManager;
54 using chromeos::ExistingUserController;
55 using chromeos::UpdateEngineClient;
56 using chromeos::User;
57 using chromeos::UserManager;
58 using chromeos::WizardController;
60 namespace {
62 void UpdateCheckCallback(AutomationJSONReply* reply,
63 UpdateEngineClient::UpdateCheckResult result) {
64 if (result == UpdateEngineClient::UPDATE_RESULT_SUCCESS)
65 reply->SendSuccess(NULL);
66 else
67 reply->SendError("update check failed");
68 delete reply;
71 } // namespace
73 #if defined(OS_CHROMEOS)
74 void TestingAutomationProvider::PowerChanged(
75 const power_manager::PowerSupplyProperties& proto) {
76 power_supply_properties_ = proto;
78 #endif
80 void TestingAutomationProvider::AcceptOOBENetworkScreen(
81 base::DictionaryValue* args,
82 IPC::Message* reply_message) {
83 WizardController* wizard_controller = WizardController::default_controller();
84 if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
85 WizardController::kNetworkScreenName) {
86 AutomationJSONReply(this, reply_message).SendError(
87 "Network screen not active.");
88 return;
90 // Observer will delete itself.
91 new WizardControllerObserver(wizard_controller, this, reply_message);
92 wizard_controller->GetNetworkScreen()->OnContinuePressed();
95 void TestingAutomationProvider::AcceptOOBEEula(base::DictionaryValue* args,
96 IPC::Message* reply_message) {
97 bool accepted;
98 bool usage_stats_reporting;
99 if (!args->GetBoolean("accepted", &accepted) ||
100 !args->GetBoolean("usage_stats_reporting", &usage_stats_reporting)) {
101 AutomationJSONReply(this, reply_message).SendError(
102 "Invalid or missing args.");
103 return;
106 WizardController* wizard_controller = WizardController::default_controller();
107 if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
108 WizardController::kEulaScreenName) {
109 AutomationJSONReply(this, reply_message).SendError(
110 "EULA screen not active.");
111 return;
113 // Observer will delete itself.
114 new WizardControllerObserver(wizard_controller, this, reply_message);
115 wizard_controller->GetEulaScreen()->OnExit(accepted, usage_stats_reporting);
118 void TestingAutomationProvider::CancelOOBEUpdate(base::DictionaryValue* args,
119 IPC::Message* reply_message) {
120 if (chromeos::StartupUtils::IsOobeCompleted()) {
121 // Update already finished.
122 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
123 return_value->SetString("next_screen",
124 WizardController::kLoginScreenName);
125 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
126 return;
128 WizardController* wizard_controller = WizardController::default_controller();
129 if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
130 WizardController::kUpdateScreenName) {
131 AutomationJSONReply(this, reply_message).SendError(
132 "Update screen not active.");
133 return;
135 // Observer will delete itself.
136 new WizardControllerObserver(wizard_controller, this, reply_message);
137 wizard_controller->GetUpdateScreen()->CancelUpdate();
140 void TestingAutomationProvider::GetLoginInfo(base::DictionaryValue* args,
141 IPC::Message* reply_message) {
142 AutomationJSONReply reply(this, reply_message);
143 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
145 const UserManager* user_manager = UserManager::Get();
146 if (!user_manager)
147 reply.SendError("No user manager!");
148 const chromeos::ScreenLocker* screen_locker =
149 chromeos::ScreenLocker::default_screen_locker();
151 return_value->SetString("login_ui_type", "webui");
152 return_value->SetBoolean("is_owner", user_manager->IsCurrentUserOwner());
153 return_value->SetBoolean("is_logged_in", user_manager->IsUserLoggedIn());
154 return_value->SetBoolean("is_screen_locked", screen_locker);
155 if (user_manager->IsUserLoggedIn()) {
156 const User* user = user_manager->GetLoggedInUser();
157 return_value->SetBoolean("is_guest", user_manager->IsLoggedInAsGuest());
158 return_value->SetString("email", user->email());
159 return_value->SetString("display_email", user->display_email());
160 switch (user->image_index()) {
161 case User::kExternalImageIndex:
162 return_value->SetString("user_image", "file");
163 break;
165 case User::kProfileImageIndex:
166 return_value->SetString("user_image", "profile");
167 break;
169 default:
170 return_value->SetInteger("user_image", user->image_index());
171 break;
175 reply.SendSuccess(return_value.get());
178 // See the note under LoginAsGuest(). CreateAccount() causes a login as guest.
179 void TestingAutomationProvider::ShowCreateAccountUI(
180 base::DictionaryValue* args, IPC::Message* reply_message) {
181 ExistingUserController* controller =
182 ExistingUserController::current_controller();
183 // Return immediately, since we're going to die before the login is finished.
184 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
185 controller->CreateAccount();
188 // Logging in as guest will cause session_manager to restart Chrome with new
189 // flags. If you used EnableChromeTesting, you will have to call it again.
190 void TestingAutomationProvider::LoginAsGuest(base::DictionaryValue* args,
191 IPC::Message* reply_message) {
192 ExistingUserController* controller =
193 ExistingUserController::current_controller();
194 // Return immediately, since we're going to die before the login is finished.
195 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
196 controller->LoginAsGuest();
199 void TestingAutomationProvider::SubmitLoginForm(base::DictionaryValue* args,
200 IPC::Message* reply_message) {
201 AutomationJSONReply reply(this, reply_message);
203 std::string username, password;
204 if (!args->GetString("username", &username) ||
205 !args->GetString("password", &password)) {
206 reply.SendError("Invalid or missing args.");
207 return;
210 chromeos::ExistingUserController* controller =
211 chromeos::ExistingUserController::current_controller();
212 if (!controller) {
213 reply.SendError("Unable to access ExistingUserController");
214 return;
217 // WebUI login.
218 chromeos::WebUILoginDisplay* webui_login_display =
219 static_cast<chromeos::WebUILoginDisplay*>(controller->login_display());
220 VLOG(2) << "TestingAutomationProvider::SubmitLoginForm "
221 << "ShowSigninScreenForCreds(" << username << ", " << password << ")";
223 webui_login_display->ShowSigninScreenForCreds(username, password);
224 reply.SendSuccess(NULL);
227 void TestingAutomationProvider::AddLoginEventObserver(
228 base::DictionaryValue* args, IPC::Message* reply_message) {
229 ExistingUserController* controller =
230 ExistingUserController::current_controller();
231 AutomationJSONReply reply(this, reply_message);
232 if (!controller) {
233 // This may happen due to SkipToLogin not being called.
234 reply.SendError("Unable to access ExistingUserController");
235 return;
238 if (!automation_event_queue_.get())
239 automation_event_queue_.reset(new AutomationEventQueue);
241 int observer_id = automation_event_queue_->AddObserver(
242 new LoginEventObserver(automation_event_queue_.get(), this));
244 // Return the observer's id.
245 base::DictionaryValue return_value;
246 return_value.SetInteger("observer_id", observer_id);
247 reply.SendSuccess(&return_value);
250 void TestingAutomationProvider::SignOut(base::DictionaryValue* args,
251 IPC::Message* reply_message) {
252 ash::Shell::GetInstance()->system_tray_delegate()->SignOut();
253 // Sign out has the side effect of restarting the session_manager
254 // and chrome, thereby severing the automation channel, so it's
255 // not really necessary to send a reply back. The next line is
256 // for consistency with other methods.
257 AutomationJSONReply(this, reply_message).SendSuccess(NULL);
260 void TestingAutomationProvider::PickUserImage(base::DictionaryValue* args,
261 IPC::Message* reply_message) {
262 std::string image_type;
263 int image_number = -1;
264 if (!args->GetString("image", &image_type)
265 && !args->GetInteger("image", &image_number)) {
266 AutomationJSONReply(this, reply_message).SendError(
267 "Invalid or missing args.");
268 return;
270 WizardController* wizard_controller = WizardController::default_controller();
271 if (!wizard_controller || wizard_controller->current_screen()->GetName() !=
272 WizardController::kUserImageScreenName) {
273 AutomationJSONReply(this, reply_message).SendError(
274 "User image screen not active.");
275 return;
277 chromeos::UserImageScreen* image_screen =
278 wizard_controller->GetUserImageScreen();
279 // Observer will delete itself unless error is returned.
280 WizardControllerObserver* observer =
281 new WizardControllerObserver(wizard_controller, this, reply_message);
282 if (image_type == "profile") {
283 image_screen->OnImageSelected("", image_type, true);
284 image_screen->OnImageAccepted();
285 } else if (image_type.empty() && image_number >= 0 &&
286 image_number < chromeos::kDefaultImagesCount) {
287 image_screen->OnImageSelected(
288 chromeos::GetDefaultImageUrl(image_number), image_type, true);
289 image_screen->OnImageAccepted();
290 } else {
291 AutomationJSONReply(this, reply_message).SendError(
292 "Invalid or missing args.");
293 delete observer;
294 return;
298 void TestingAutomationProvider::SkipToLogin(base::DictionaryValue* args,
299 IPC::Message* reply_message) {
300 bool skip_post_login_screens;
301 // The argument name is a legacy. If set to |true|, this argument causes any
302 // screens that may otherwise be shown after login (registration, Terms of
303 // Service, user image selection) to be skipped.
304 if (!args->GetBoolean("skip_image_selection", &skip_post_login_screens)) {
305 AutomationJSONReply reply(this, reply_message);
306 reply.SendError("Invalid or missing args.");
307 return;
309 if (skip_post_login_screens)
310 WizardController::SkipPostLoginScreensForTesting();
312 WizardController* wizard_controller = WizardController::default_controller();
313 if (!wizard_controller) {
314 AutomationJSONReply reply(this, reply_message);
315 if (ExistingUserController::current_controller()) {
316 // Already at login screen.
317 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
318 return_value->SetString("next_screen",
319 WizardController::kLoginScreenName);
320 reply.SendSuccess(return_value.get());
321 } else {
322 reply.SendError("OOBE not active.");
324 return;
327 // Observer will delete itself.
328 WizardControllerObserver* observer =
329 new WizardControllerObserver(wizard_controller, this, reply_message);
330 observer->set_screen_to_wait_for(WizardController::kLoginScreenName);
331 wizard_controller->SkipToLoginForTesting(chromeos::LoginScreenContext());
334 void TestingAutomationProvider::GetOOBEScreenInfo(base::DictionaryValue* args,
335 IPC::Message* reply_message) {
336 static const char kScreenNameKey[] = "screen_name";
337 AutomationJSONReply reply(this, reply_message);
338 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
340 WizardController* wizard_controller = WizardController::default_controller();
341 if (wizard_controller) {
342 if (wizard_controller->login_screen_started()) {
343 return_value->SetString(kScreenNameKey,
344 WizardController::kLoginScreenName);
345 } else {
346 return_value->SetString(kScreenNameKey,
347 wizard_controller->current_screen()->GetName());
349 } else if (ExistingUserController::current_controller()) {
350 return_value->SetString(kScreenNameKey, WizardController::kLoginScreenName);
351 } else {
352 // Already logged in.
353 reply.SendSuccess(NULL);
354 return;
356 reply.SendSuccess(return_value.get());
359 void TestingAutomationProvider::LockScreen(base::DictionaryValue* args,
360 IPC::Message* reply_message) {
361 new ScreenLockUnlockObserver(this, reply_message, true);
362 DBusThreadManager::Get()->GetSessionManagerClient()->RequestLockScreen();
365 void TestingAutomationProvider::UnlockScreen(base::DictionaryValue* args,
366 IPC::Message* reply_message) {
367 std::string password;
368 if (!args->GetString("password", &password)) {
369 AutomationJSONReply(this, reply_message).SendError(
370 "Invalid or missing args.");
371 return;
374 chromeos::ScreenLocker* screen_locker =
375 chromeos::ScreenLocker::default_screen_locker();
376 if (!screen_locker) {
377 AutomationJSONReply(this, reply_message).SendError(
378 "No default screen locker. Are you sure the screen is locked?");
379 return;
382 new ScreenUnlockObserver(this, reply_message);
383 screen_locker->AuthenticateByPassword(password);
386 // Signing out could have undesirable side effects: session_manager is
387 // killed, so its children, including chrome and the window manager, will
388 // also be killed. Anything owned by chronos will probably be killed.
389 void TestingAutomationProvider::SignoutInScreenLocker(
390 base::DictionaryValue* args, IPC::Message* reply_message) {
391 AutomationJSONReply reply(this, reply_message);
392 chromeos::ScreenLocker* screen_locker =
393 chromeos::ScreenLocker::default_screen_locker();
394 if (!screen_locker) {
395 reply.SendError(
396 "No default screen locker. Are you sure the screen is locked?");
397 return;
400 // Send success before stopping session because if we're a child of
401 // session manager then we'll die when the session is stopped.
402 reply.SendSuccess(NULL);
403 screen_locker->Signout();
406 void TestingAutomationProvider::GetBatteryInfo(base::DictionaryValue* args,
407 IPC::Message* reply_message) {
408 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
410 const bool battery_is_present = power_supply_properties_.battery_state() !=
411 power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT;
412 const bool line_power_on = power_supply_properties_.external_power() !=
413 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
415 return_value->SetBoolean("battery_is_present", battery_is_present);
416 return_value->SetBoolean("line_power_on", line_power_on);
418 if (battery_is_present) {
419 const bool battery_is_full = power_supply_properties_.battery_state() ==
420 power_manager::PowerSupplyProperties_BatteryState_FULL;
421 return_value->SetBoolean("battery_fully_charged", battery_is_full);
422 return_value->SetDouble("battery_percentage",
423 power_supply_properties_.battery_percent());
424 if (line_power_on) {
425 int64 time = power_supply_properties_.battery_time_to_full_sec();
426 if (time > 0 || battery_is_full)
427 return_value->SetInteger("battery_seconds_to_full", time);
428 } else {
429 int64 time = power_supply_properties_.battery_time_to_empty_sec();
430 if (time > 0)
431 return_value->SetInteger("battery_seconds_to_empty", time);
435 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
438 void TestingAutomationProvider::ExecuteJavascriptInOOBEWebUI(
439 base::DictionaryValue* args, IPC::Message* reply_message) {
440 std::string javascript, frame_xpath;
441 if (!args->GetString("javascript", &javascript)) {
442 AutomationJSONReply(this, reply_message)
443 .SendError("'javascript' missing or invalid");
444 return;
446 if (!args->GetString("frame_xpath", &frame_xpath)) {
447 AutomationJSONReply(this, reply_message)
448 .SendError("'frame_xpath' missing or invalid");
449 return;
451 const UserManager* user_manager = UserManager::Get();
452 if (!user_manager) {
453 AutomationJSONReply(this, reply_message).SendError(
454 "No user manager!");
455 return;
457 if (user_manager->IsUserLoggedIn()) {
458 AutomationJSONReply(this, reply_message).SendError(
459 "User is already logged in.");
460 return;
462 ExistingUserController* controller =
463 ExistingUserController::current_controller();
464 if (!controller) {
465 AutomationJSONReply(this, reply_message).SendError(
466 "Unable to access ExistingUserController");
467 return;
469 chromeos::LoginDisplayHostImpl* webui_host =
470 static_cast<chromeos::LoginDisplayHostImpl*>(
471 controller->login_display_host());
472 content::WebContents* web_contents =
473 webui_host->GetOobeUI()->web_ui()->GetWebContents();
475 new DomOperationMessageSender(this, reply_message, true);
476 ExecuteJavascriptInRenderViewFrame(base::ASCIIToUTF16(frame_xpath),
477 base::ASCIIToUTF16(javascript),
478 reply_message,
479 web_contents->GetRenderViewHost());
482 void TestingAutomationProvider::EnableSpokenFeedback(
483 base::DictionaryValue* args, IPC::Message* reply_message) {
484 AutomationJSONReply reply(this, reply_message);
485 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
486 bool enabled;
487 if (!args->GetBoolean("enabled", &enabled)) {
488 reply.SendError("Invalid or missing args.");
489 return;
491 chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(
492 enabled, ash::A11Y_NOTIFICATION_NONE);
494 reply.SendSuccess(return_value.get());
497 void TestingAutomationProvider::IsSpokenFeedbackEnabled(
498 base::DictionaryValue* args, IPC::Message* reply_message) {
499 AutomationJSONReply reply(this, reply_message);
500 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
501 return_value->SetBoolean(
502 "spoken_feedback",
503 chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
504 reply.SendSuccess(return_value.get());
507 void TestingAutomationProvider::GetTimeInfo(Browser* browser,
508 base::DictionaryValue* args,
509 IPC::Message* reply_message) {
510 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
511 base::Time time(base::Time::Now());
512 bool use_24hour_clock = browser && browser->profile()->GetPrefs()->GetBoolean(
513 prefs::kUse24HourClock);
514 base::HourClockType hour_clock_type =
515 use_24hour_clock ? base::k24HourClock : base::k12HourClock;
516 base::string16 display_time = base::TimeFormatTimeOfDayWithHourClockType(
517 time, hour_clock_type, base::kDropAmPm);
518 base::string16 timezone =
519 chromeos::system::TimezoneSettings::GetInstance()->GetCurrentTimezoneID();
520 return_value->SetString("display_time", display_time);
521 return_value->SetString("display_date", base::TimeFormatFriendlyDate(time));
522 return_value->SetString("timezone", timezone);
523 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
526 void TestingAutomationProvider::GetTimeInfo(base::DictionaryValue* args,
527 IPC::Message* reply_message) {
528 GetTimeInfo(NULL, args, reply_message);
531 void TestingAutomationProvider::SetTimezone(base::DictionaryValue* args,
532 IPC::Message* reply_message) {
533 AutomationJSONReply reply(this, reply_message);
534 std::string timezone_id;
535 if (!args->GetString("timezone", &timezone_id)) {
536 reply.SendError("Invalid or missing args.");
537 return;
539 chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
540 settings->SetString(chromeos::kSystemTimezone, timezone_id);
541 reply.SendSuccess(NULL);
544 void TestingAutomationProvider::UpdateCheck(
545 base::DictionaryValue* args,
546 IPC::Message* reply_message) {
547 AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message);
548 DBusThreadManager::Get()->GetUpdateEngineClient()
549 ->RequestUpdateCheck(base::Bind(UpdateCheckCallback, reply));
552 void TestingAutomationProvider::GetVolumeInfo(base::DictionaryValue* args,
553 IPC::Message* reply_message) {
554 AutomationJSONReply reply(this, reply_message);
555 scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
556 chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
557 if (!audio_handler) {
558 reply.SendError("CrasAudioHandler not initialized.");
559 return;
561 return_value->SetDouble("volume", audio_handler->GetOutputVolumePercent());
562 return_value->SetBoolean("is_mute", audio_handler->IsOutputMuted());
563 reply.SendSuccess(return_value.get());
566 void TestingAutomationProvider::SetVolume(base::DictionaryValue* args,
567 IPC::Message* reply_message) {
568 AutomationJSONReply reply(this, reply_message);
569 double volume_percent;
570 if (!args->GetDouble("volume", &volume_percent)) {
571 reply.SendError("Invalid or missing args.");
572 return;
574 chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
575 if (!audio_handler) {
576 reply.SendError("CrasAudioHandler not initialized.");
577 return;
579 audio_handler->SetOutputVolumePercent(volume_percent);
580 reply.SendSuccess(NULL);
583 void TestingAutomationProvider::SetMute(base::DictionaryValue* args,
584 IPC::Message* reply_message) {
585 AutomationJSONReply reply(this, reply_message);
586 bool mute;
587 if (!args->GetBoolean("mute", &mute)) {
588 reply.SendError("Invalid or missing args.");
589 return;
591 chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
592 if (!audio_handler) {
593 reply.SendError("CrasAudioHandler not initialized.");
594 return;
596 audio_handler->SetOutputMute(mute);
597 reply.SendSuccess(NULL);
600 void TestingAutomationProvider::OpenCrosh(base::DictionaryValue* args,
601 IPC::Message* reply_message) {
602 new NavigationNotificationObserver(
603 NULL, this, reply_message, 1, false, true);
604 ash::Shell::GetInstance()->new_window_delegate()->OpenCrosh();
607 void TestingAutomationProvider::AddChromeosObservers() {
608 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
609 AddObserver(this);
612 void TestingAutomationProvider::RemoveChromeosObservers() {
613 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
614 RemoveObserver(this);