diff options
author | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-05 03:25:56 +0000 |
---|---|---|
committer | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-05 03:25:56 +0000 |
commit | 0f42f11ccbb7de2dbea2404481985a9473e694bd (patch) | |
tree | c7f1fdce20a699e0e2d2dfe275f19fe311cdca53 | |
parent | 2a75eccb132d1027985f5e1909de3fa19a008227 (diff) | |
download | chromium_src-0f42f11ccbb7de2dbea2404481985a9473e694bd.zip chromium_src-0f42f11ccbb7de2dbea2404481985a9473e694bd.tar.gz chromium_src-0f42f11ccbb7de2dbea2404481985a9473e694bd.tar.bz2 |
kiosk: Network connectivity test during launch.
- Add NetworkStateInformer and ErrorScreenActor to
AppLaunchSplashScreenHandler;
- AppLaunchSplashScreenHandler sends network state
to its delegate (AppLaunchController) during network
check;
- AppLaunchController decides when to show network
configure UI and call AppLaunchSplashScreenActor
to show it (via ErrorScreenActor);
- Show network config UI for enterprise kiosk;
- Add a 'Reboot' button for kiosk network error;
- Add a PromptForNetworkWhenOffline boolean field to
DeviceLocalAccountsProto to control whether to show
network config UI for enterprise managed kiosk;
BUG=314710
TEST=KioskTest.LaunchAppNetworkDown/Portal
Review URL: https://codereview.chromium.org/79113002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238873 0039d316-1c4b-4281-b951-d872f2087c98
24 files changed, 448 insertions, 197 deletions
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json index f0f5d94..074416d 100644 --- a/chrome/app/policy/policy_templates.json +++ b/chrome/app/policy/policy_templates.json @@ -118,7 +118,7 @@ # persistent IDs for all fields (but not for groups!) are needed. These are # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # because doing so would break the deployed wire format! -# For your editing convenience: highest ID currently used: 249 +# For your editing convenience: highest ID currently used: 250 # # Placeholders: # The following placeholder strings are automatically substituted: @@ -3886,7 +3886,6 @@ }, 'supported_on': ['chrome_os:25-'], 'device_only': True, - 'future': True, 'features': { 'dynamic_refresh': True, }, @@ -3946,7 +3945,6 @@ 'features': { 'dynamic_refresh': True, }, - 'future': True, 'example_value': True, 'id': 202, 'caption': '''Enable bailout keyboard shortcut for auto-login''', @@ -3957,6 +3955,24 @@ If this policy is set to False, zero-delay auto-login (if configured) cannot be bypassed.''' }, { + 'name': 'DeviceLocalAccountPromptForNetworkWhenOffline', + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'supported_on': ['chrome_os:33-'], + 'device_only': True, + 'features': { + 'dynamic_refresh': True, + }, + 'example_value': True, + 'id': 250, + 'caption': '''Enable network configuration prompt when offline''', + 'desc': '''Enable network configuration prompt when offline. + + If this policy is unset or set to True and a device-local account is configured for zero-delay auto-login and the device does not have access to the Internet, <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> will show a network configuration prompt. + + If this policy is set to False, an error message will be displayed instead of the network configuration prompt.''' + }, + { 'name': 'BackgroundModeEnabled', 'type': 'main', 'schema': { 'type': 'boolean' }, diff --git a/chrome/browser/chromeos/app_mode/app_launch_utils.cc b/chrome/browser/chromeos/app_mode/app_launch_utils.cc index 21efeb9..aee250c 100644 --- a/chrome/browser/chromeos/app_mode/app_launch_utils.cc +++ b/chrome/browser/chromeos/app_mode/app_launch_utils.cc @@ -14,15 +14,13 @@ namespace chromeos { // A simple manager for the app launch that starts the launch // and deletes itself when the launch finishes. On launch failure, // it exits the browser process. -class AppLaunchManager : public StartupAppLauncher::Observer { +class AppLaunchManager : public StartupAppLauncher::Delegate { public: AppLaunchManager(Profile* profile, const std::string& app_id) - : waiting_for_network_(false) { - startup_app_launcher_.reset(new StartupAppLauncher(profile, app_id)); + : startup_app_launcher_(new StartupAppLauncher(profile, app_id, this)) { } void Start() { - startup_app_launcher_->AddObserver(this); startup_app_launcher_->Initialize(); } @@ -31,34 +29,19 @@ class AppLaunchManager : public StartupAppLauncher::Observer { void Cleanup() { delete this; } - void OnNetworkWaitTimedout() { - DCHECK(waiting_for_network_); - LOG(ERROR) << "Timed out while waiting for network during app launch."; - OnLaunchFailed(KioskAppLaunchError::UNABLE_TO_INSTALL); + // StartupAppLauncher::Delegate overrides: + virtual void InitializeNetwork() OVERRIDE { + // This is on crash-restart path and assumes network is online. + // TODO(xiyuan): Remove the crash-restart path for kiosk or add proper + // network configure handling. + startup_app_launcher_->ContinueWithNetworkReady(); } - - // StartupAppLauncher::Observer overrides: virtual void OnLoadingOAuthFile() OVERRIDE {} virtual void OnInitializingTokenService() OVERRIDE {} - - virtual void OnInitializingNetwork() OVERRIDE { - waiting_for_network_ = true; - const int kMaxNetworkWaitSeconds = 5 * 60; - network_wait_timer_.Start( - FROM_HERE, - base::TimeDelta::FromSeconds(kMaxNetworkWaitSeconds), - this, &AppLaunchManager::OnNetworkWaitTimedout); - } - - virtual void OnInstallingApp() OVERRIDE { - waiting_for_network_ = false; - network_wait_timer_.Stop(); - } - + virtual void OnInstallingApp() OVERRIDE {} virtual void OnReadyToLaunch() OVERRIDE { startup_app_launcher_->LaunchApp(); } - virtual void OnLaunchSucceeded() OVERRIDE { Cleanup(); } virtual void OnLaunchFailed(KioskAppLaunchError::Error error) OVERRIDE { KioskAppLaunchError::Save(error); @@ -66,8 +49,6 @@ class AppLaunchManager : public StartupAppLauncher::Observer { Cleanup(); } - base::OneShotTimer<AppLaunchManager> network_wait_timer_; - bool waiting_for_network_; scoped_ptr<StartupAppLauncher> startup_app_launcher_; DISALLOW_COPY_AND_ASSIGN(AppLaunchManager); diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc index 4bdae77..9c269b5 100644 --- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc +++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc @@ -54,9 +54,12 @@ bool IsAppInstalled(Profile* profile, const std::string& app_id) { StartupAppLauncher::StartupAppLauncher(Profile* profile, - const std::string& app_id) + const std::string& app_id, + StartupAppLauncher::Delegate* delegate) : profile_(profile), app_id_(app_id), + delegate_(delegate), + install_attempted_(false), ready_to_launch_(false) { DCHECK(profile_); DCHECK(Extension::IdIsValid(app_id_)); @@ -67,25 +70,22 @@ StartupAppLauncher::~StartupAppLauncher() { // through a user bailout shortcut. ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) ->RemoveObserver(this); - net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); } void StartupAppLauncher::Initialize() { - DVLOG(1) << "Starting... connection = " - << net::NetworkChangeNotifier::GetConnectionType(); StartLoadingOAuthFile(); } -void StartupAppLauncher::AddObserver(Observer* observer) { - observer_list_.AddObserver(observer); -} - -void StartupAppLauncher::RemoveObserver(Observer* observer) { - observer_list_.RemoveObserver(observer); +void StartupAppLauncher::ContinueWithNetworkReady() { + // Starts install if it is not started. + if (!install_attempted_) { + install_attempted_ = true; + BeginInstall(); + } } void StartupAppLauncher::StartLoadingOAuthFile() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnLoadingOAuthFile()); + delegate_->OnLoadingOAuthFile(); KioskOAuthParams* auth_params = new KioskOAuthParams(); BrowserThread::PostBlockingPoolTaskAndReply( @@ -137,17 +137,11 @@ void StartupAppLauncher::OnOAuthFileLoaded(KioskOAuthParams* auth_params) { } void StartupAppLauncher::InitializeNetwork() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnInitializingNetwork()); - - // TODO(tengs): Use NetworkStateInformer instead because it can handle - // portal and proxy detection. We will need to do some refactoring to - // make NetworkStateInformer more independent from the WebUI handlers. - net::NetworkChangeNotifier::AddNetworkChangeObserver(this); - OnNetworkChanged(net::NetworkChangeNotifier::GetConnectionType()); + delegate_->InitializeNetwork(); } void StartupAppLauncher::InitializeTokenService() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnInitializingTokenService()); + delegate_->OnInitializingTokenService(); ProfileOAuth2TokenService* profile_token_service = ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); @@ -190,14 +184,14 @@ void StartupAppLauncher::OnRefreshTokensLoaded() { } void StartupAppLauncher::OnLaunchSuccess() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnLaunchSucceeded()); + delegate_->OnLaunchSucceeded(); } void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) { LOG(ERROR) << "App launch failed, error: " << error; DCHECK_NE(KioskAppLaunchError::NONE, error); - FOR_EACH_OBSERVER(Observer, observer_list_, OnLaunchFailed(error)); + delegate_->OnLaunchFailed(error); } void StartupAppLauncher::LaunchApp() { @@ -231,10 +225,7 @@ void StartupAppLauncher::LaunchApp() { } void StartupAppLauncher::BeginInstall() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnInstallingApp()); - - DVLOG(1) << "BeginInstall... connection = " - << net::NetworkChangeNotifier::GetConnectionType(); + delegate_->OnInstallingApp(); if (IsAppInstalled(profile_, app_id_)) { OnReadyToLaunch(); @@ -269,21 +260,7 @@ void StartupAppLauncher::InstallCallback(bool success, void StartupAppLauncher::OnReadyToLaunch() { ready_to_launch_ = true; - FOR_EACH_OBSERVER(Observer, observer_list_, OnReadyToLaunch()); -} - -void StartupAppLauncher::OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) { - DVLOG(1) << "OnNetworkChanged... connection = " - << net::NetworkChangeNotifier::GetConnectionType(); - if (!net::NetworkChangeNotifier::IsOffline()) { - DVLOG(1) << "Network up and running!"; - net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); - - BeginInstall(); - } else { - DVLOG(1) << "Network not running yet!"; - } + delegate_->OnReadyToLaunch(); } } // namespace chromeos diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.h b/chrome/browser/chromeos/app_mode/startup_app_launcher.h index b7d7baf..43f7cbf 100644 --- a/chrome/browser/chromeos/app_mode/startup_app_launcher.h +++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.h @@ -10,10 +10,8 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" #include "google_apis/gaia/oauth2_token_service.h" -#include "net/base/network_change_notifier.h" class Profile; @@ -34,37 +32,40 @@ namespace chromeos { // - If all goes good, launches the app and finish the flow; class StartupAppLauncher : public base::SupportsWeakPtr<StartupAppLauncher>, - public OAuth2TokenService::Observer, - public net::NetworkChangeNotifier::NetworkChangeObserver { + public OAuth2TokenService::Observer { public: - class Observer { + class Delegate { public: + // Invoked to perform actual network initialization work. Note the app + // launch flow is paused until ContinueWithNetworkReady is called. + virtual void InitializeNetwork() = 0; + virtual void OnLoadingOAuthFile() = 0; virtual void OnInitializingTokenService() = 0; - virtual void OnInitializingNetwork() = 0; virtual void OnInstallingApp() = 0; virtual void OnReadyToLaunch() = 0; virtual void OnLaunchSucceeded() = 0; virtual void OnLaunchFailed(KioskAppLaunchError::Error error) = 0; protected: - virtual ~Observer() {} + virtual ~Delegate() {} }; - StartupAppLauncher(Profile* profile, const std::string& app_id); + StartupAppLauncher(Profile* profile, + const std::string& app_id, + Delegate* delegate); virtual ~StartupAppLauncher(); // Prepares the environment for an app launch. void Initialize(); + // Continues the initialization after network is ready. + void ContinueWithNetworkReady(); + // Launches the app after the initialization is successful. void LaunchApp(); - // Add and remove observers for app launch procedure. - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - private: // OAuth parameters from /home/chronos/kiosk_auth file. struct KioskOAuthParams { @@ -91,13 +92,10 @@ class StartupAppLauncher virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE; virtual void OnRefreshTokensLoaded() OVERRIDE; - // net::NetworkChangeNotifier::NetworkChangeObserver overrides: - virtual void OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) OVERRIDE; - Profile* profile_; const std::string app_id_; - ObserverList<Observer> observer_list_; + Delegate* delegate_; + bool install_attempted_; bool ready_to_launch_; scoped_refptr<extensions::WebstoreStandaloneInstaller> installer_; diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc index ecaf9ae..cf415c0 100644 --- a/chrome/browser/chromeos/login/app_launch_controller.cc +++ b/chrome/browser/chromeos/login/app_launch_controller.cc @@ -10,6 +10,7 @@ #include "base/json/json_file_value_serializer.h" #include "base/time/time.h" #include "base/values.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" @@ -19,7 +20,9 @@ #include "chrome/browser/chromeos/login/oobe_display.h" #include "chrome/browser/chromeos/login/screens/error_screen_actor.h" #include "chrome/browser/chromeos/login/webui_login_view.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/policy/browser_policy_connector.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" @@ -40,8 +43,10 @@ const int kAppInstallSplashScreenMinTimeMS = 3000; bool AppLaunchController::skip_splash_wait_ = false; int AppLaunchController::network_wait_time_ = 10; base::Closure* AppLaunchController::network_timeout_callback_ = NULL; -AppLaunchController::CanConfigureNetworkCallback* +AppLaunchController::ReturnBoolCallback* AppLaunchController::can_configure_network_callback_ = NULL; +AppLaunchController::ReturnBoolCallback* + AppLaunchController::need_owner_auth_to_configure_network_callback_ = NULL; //////////////////////////////////////////////////////////////////////////////// // AppLaunchController::AppWindowWatcher @@ -88,15 +93,12 @@ AppLaunchController::AppLaunchController(const std::string& app_id, oobe_display_(oobe_display), app_launch_splash_screen_actor_( oobe_display_->GetAppLaunchSplashScreenActor()), - error_screen_actor_(oobe_display_->GetErrorScreenActor()), webui_visible_(false), launcher_ready_(false), waiting_for_network_(false), network_wait_timedout_(false), showing_network_dialog_(false), launch_splash_start_time_(0) { - signin_screen_.reset(new AppLaunchSigninScreen( - static_cast<OobeUI*>(oobe_display_), this)); } AppLaunchController::~AppLaunchController() { @@ -122,28 +124,40 @@ void AppLaunchController::StartAppLaunch() { kiosk_profile_loader_->Start(); } +// static void AppLaunchController::SkipSplashWaitForTesting() { skip_splash_wait_ = true; } +// static void AppLaunchController::SetNetworkWaitForTesting(int wait_time_secs) { network_wait_time_ = wait_time_secs; } +// static void AppLaunchController::SetNetworkTimeoutCallbackForTesting( base::Closure* callback) { network_timeout_callback_ = callback; } +// static void AppLaunchController::SetCanConfigureNetworkCallbackForTesting( - CanConfigureNetworkCallback* can_configure_network_callback) { + ReturnBoolCallback* can_configure_network_callback) { can_configure_network_callback_ = can_configure_network_callback; } +// static +void AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting( + ReturnBoolCallback* need_owner_auth_callback) { + need_owner_auth_to_configure_network_callback_ = need_owner_auth_callback; +} + void AppLaunchController::OnConfigureNetwork() { DCHECK(profile_); showing_network_dialog_ = true; - if (CanConfigureNetwork()) { + if (CanConfigureNetwork() && NeedOwnerAuthToConfigureNetwork()) { + signin_screen_.reset(new AppLaunchSigninScreen( + static_cast<OobeUI*>(oobe_display_), this)); signin_screen_->Show(); } else { // If kiosk mode was configured through enterprise policy, we may @@ -155,12 +169,7 @@ void AppLaunchController::OnConfigureNetwork() { } void AppLaunchController::OnOwnerSigninSuccess() { - error_screen_actor_->SetErrorState( - ErrorScreen::ERROR_STATE_OFFLINE, std::string()); - error_screen_actor_->SetUIState(ErrorScreen::UI_STATE_KIOSK_MODE); - - error_screen_actor_->Show(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH, NULL); - + app_launch_splash_screen_actor_->ShowNetworkConfigureUI(); signin_screen_.reset(); } @@ -183,13 +192,22 @@ void AppLaunchController::OnCancelAppLaunch() { OnLaunchFailed(KioskAppLaunchError::USER_CANCEL); } +void AppLaunchController::OnNetworkStateChanged(bool online) { + if (!waiting_for_network_) + return; + + if (online) + startup_app_launcher_->ContinueWithNetworkReady(); + else if (network_wait_timedout_) + MaybeShowNetworkConfigureUI(); +} + void AppLaunchController::OnProfileLoaded(Profile* profile) { DVLOG(1) << "Profile loaded... Starting app launch."; profile_ = profile; kiosk_profile_loader_.reset(); - startup_app_launcher_.reset(new StartupAppLauncher(profile_, app_id_)); - startup_app_launcher_->AddObserver(this); + startup_app_launcher_.reset(new StartupAppLauncher(profile_, app_id_, this)); startup_app_launcher_->Initialize(); } @@ -212,12 +230,7 @@ void AppLaunchController::OnNetworkWaitTimedout() { << net::NetworkChangeNotifier::GetConnectionType(); network_wait_timedout_ = true; - if (CanConfigureNetwork()) { - app_launch_splash_screen_actor_->ToggleNetworkConfig(true); - } else { - app_launch_splash_screen_actor_->UpdateAppLaunchState( - AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT); - } + MaybeShowNetworkConfigureUI(); if (network_timeout_callback_) network_timeout_callback_->Run(); @@ -232,23 +245,43 @@ bool AppLaunchController::CanConfigureNetwork() { if (can_configure_network_callback_) return can_configure_network_callback_->Run(); + if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) { + bool should_prompt; + if (CrosSettings::Get()->GetBoolean( + kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline, + &should_prompt)) { + return should_prompt; + } + + // Default to true to allow network configuration if the policy is missing. + return true; + } + return !UserManager::Get()->GetOwnerEmail().empty(); } -void AppLaunchController::OnLoadingOAuthFile() { - app_launch_splash_screen_actor_->UpdateAppLaunchState( - AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE); -} +bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() { + if (need_owner_auth_to_configure_network_callback_) + return need_owner_auth_to_configure_network_callback_->Run(); -void AppLaunchController::OnInitializingTokenService() { - app_launch_splash_screen_actor_->UpdateAppLaunchState( - AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE); + return !g_browser_process->browser_policy_connector()->IsEnterpriseManaged(); } -void AppLaunchController::OnInitializingNetwork() { - app_launch_splash_screen_actor_->UpdateAppLaunchState( - AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK); +void AppLaunchController::MaybeShowNetworkConfigureUI() { + if (CanConfigureNetwork()) { + if (NeedOwnerAuthToConfigureNetwork()) { + app_launch_splash_screen_actor_->ToggleNetworkConfig(true); + } else { + showing_network_dialog_ = true; + app_launch_splash_screen_actor_->ShowNetworkConfigureUI(); + } + } else { + app_launch_splash_screen_actor_->UpdateAppLaunchState( + AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT); + } +} +void AppLaunchController::InitializeNetwork() { // Show the network configration dialog if network is not initialized // after a brief wait time. waiting_for_network_ = true; @@ -256,12 +289,26 @@ void AppLaunchController::OnInitializingNetwork() { FROM_HERE, base::TimeDelta::FromSeconds(network_wait_time_), this, &AppLaunchController::OnNetworkWaitTimedout); + + app_launch_splash_screen_actor_->UpdateAppLaunchState( + AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK); +} + +void AppLaunchController::OnLoadingOAuthFile() { + app_launch_splash_screen_actor_->UpdateAppLaunchState( + AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE); +} + +void AppLaunchController::OnInitializingTokenService() { + app_launch_splash_screen_actor_->UpdateAppLaunchState( + AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE); } void AppLaunchController::OnInstallingApp() { app_launch_splash_screen_actor_->UpdateAppLaunchState( AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION); + waiting_for_network_ = false; network_wait_timer_.Stop(); app_launch_splash_screen_actor_->ToggleNetworkConfig(false); diff --git a/chrome/browser/chromeos/login/app_launch_controller.h b/chrome/browser/chromeos/login/app_launch_controller.h index 382cb55..be2d463 100644 --- a/chrome/browser/chromeos/login/app_launch_controller.h +++ b/chrome/browser/chromeos/login/app_launch_controller.h @@ -17,7 +17,6 @@ #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h" #include "chrome/browser/chromeos/login/app_launch_signin_screen.h" #include "chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h" -#include "chrome/browser/chromeos/login/screens/error_screen_actor.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -36,11 +35,11 @@ class AppLaunchController : public base::SupportsWeakPtr<AppLaunchController>, public AppLaunchSplashScreenActor::Delegate, public KioskProfileLoader::Delegate, - public StartupAppLauncher::Observer, + public StartupAppLauncher::Delegate, public AppLaunchSigninScreen::Delegate, public content::NotificationObserver { public: - typedef base::Callback<bool()> CanConfigureNetworkCallback; + typedef base::Callback<bool()> ReturnBoolCallback; AppLaunchController(const std::string& app_id, LoginDisplayHost* host, @@ -59,7 +58,9 @@ class AppLaunchController static void SetNetworkTimeoutCallbackForTesting(base::Closure* callback); static void SetNetworkWaitForTesting(int wait_time_secs); static void SetCanConfigureNetworkCallbackForTesting( - CanConfigureNetworkCallback* can_configure_network_callback); + ReturnBoolCallback* can_configure_network_callback); + static void SetNeedOwnerAuthToConfigureNetworkCallbackForTesting( + ReturnBoolCallback* need_owner_auth_callback); private: // A class to watch app window creation. @@ -74,6 +75,13 @@ class AppLaunchController // Whether the network could be configured during launching. bool CanConfigureNetwork(); + // Whether the owner password is needed to configure network. + bool NeedOwnerAuthToConfigureNetwork(); + + // Show network configuration UI if it is allowed. For consumer mode, + // owner password might be checked before showing the network configure UI. + void MaybeShowNetworkConfigureUI(); + // KioskProfileLoader::Delegate overrides: virtual void OnProfileLoaded(Profile* profile) OVERRIDE; virtual void OnProfileLoadFailed(KioskAppLaunchError::Error error) OVERRIDE; @@ -81,11 +89,12 @@ class AppLaunchController // AppLaunchSplashScreenActor::Delegate overrides: virtual void OnConfigureNetwork() OVERRIDE; virtual void OnCancelAppLaunch() OVERRIDE; + virtual void OnNetworkStateChanged(bool online) OVERRIDE; - // StartupAppLauncher::Observer overrides: + // StartupAppLauncher::Delegate overrides: + virtual void InitializeNetwork() OVERRIDE; virtual void OnLoadingOAuthFile() OVERRIDE; virtual void OnInitializingTokenService() OVERRIDE; - virtual void OnInitializingNetwork() OVERRIDE; virtual void OnInstallingApp() OVERRIDE; virtual void OnReadyToLaunch() OVERRIDE; virtual void OnLaunchSucceeded() OVERRIDE; @@ -104,7 +113,6 @@ class AppLaunchController LoginDisplayHost* host_; OobeDisplay* oobe_display_; AppLaunchSplashScreenActor* app_launch_splash_screen_actor_; - ErrorScreenActor* error_screen_actor_; scoped_ptr<KioskProfileLoader> kiosk_profile_loader_; scoped_ptr<StartupAppLauncher> startup_app_launcher_; scoped_ptr<AppLaunchSigninScreen> signin_screen_; @@ -123,7 +131,8 @@ class AppLaunchController static bool skip_splash_wait_; static int network_wait_time_; static base::Closure* network_timeout_callback_; - static CanConfigureNetworkCallback* can_configure_network_callback_; + static ReturnBoolCallback* can_configure_network_callback_; + static ReturnBoolCallback* need_owner_auth_to_configure_network_callback_; DISALLOW_COPY_AND_ASSIGN(AppLaunchController); }; diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc index fd65deb..acdab07 100644 --- a/chrome/browser/chromeos/login/kiosk_browsertest.cc +++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc @@ -10,6 +10,7 @@ #include "ash/shell.h" #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/callback.h" #include "base/command_line.h" #include "base/location.h" #include "base/memory/scoped_ptr.h" @@ -32,6 +33,7 @@ #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/webui_login_display.h" #include "chrome/browser/chromeos/login/wizard_controller.h" +#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" @@ -102,6 +104,9 @@ const char kTestEnterpriseServiceAccountId[] = "service_account@example.com"; const char kTestRefreshToken[] = "fake-refresh-token"; const char kTestAccessToken[] = "fake-access-token"; +// Note the path name must be the same as in shill stub. +const char kStubEthernetServicePath[] = "eth1"; + // Helper function for GetConsumerKioskModeStatusCallback. void ConsumerKioskModeStatusCheck( KioskAppManager::ConsumerKioskModeStatus* out_status, @@ -136,58 +141,44 @@ void CopyTokenService(DeviceOAuth2TokenService** out_token_service, // Helper functions for CanConfigureNetwork mock. class ScopedCanConfigureNetwork { public: - explicit ScopedCanConfigureNetwork(bool can_configure) + ScopedCanConfigureNetwork(bool can_configure, bool needs_owner_auth) : can_configure_(can_configure), - callback_(base::Bind(&ScopedCanConfigureNetwork::CanConfigureNetwork, - base::Unretained(this))) { - AppLaunchController::SetCanConfigureNetworkCallbackForTesting(&callback_); + needs_owner_auth_(needs_owner_auth), + can_configure_network_callback_( + base::Bind(&ScopedCanConfigureNetwork::CanConfigureNetwork, + base::Unretained(this))), + needs_owner_auth_callback_(base::Bind( + &ScopedCanConfigureNetwork::NeedsOwnerAuthToConfigureNetwork, + base::Unretained(this))) { + AppLaunchController::SetCanConfigureNetworkCallbackForTesting( + &can_configure_network_callback_); + AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting( + &needs_owner_auth_callback_); } ~ScopedCanConfigureNetwork() { AppLaunchController::SetCanConfigureNetworkCallbackForTesting(NULL); + AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting( + NULL); } bool CanConfigureNetwork() { return can_configure_; } + bool NeedsOwnerAuthToConfigureNetwork() { + return needs_owner_auth_; + } + private: bool can_configure_; - AppLaunchController::CanConfigureNetworkCallback callback_; + bool needs_owner_auth_; + AppLaunchController::ReturnBoolCallback can_configure_network_callback_; + AppLaunchController::ReturnBoolCallback needs_owner_auth_callback_; DISALLOW_COPY_AND_ASSIGN(ScopedCanConfigureNetwork); }; } // namespace -// Fake NetworkChangeNotifier used to simulate network connectivity. -class FakeNetworkChangeNotifier : public net::NetworkChangeNotifier { - public: - FakeNetworkChangeNotifier() : connection_type_(CONNECTION_NONE) {} - - virtual ConnectionType GetCurrentConnectionType() const OVERRIDE { - return connection_type_; - } - - void GoOnline() { - SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - } - - void GoOffline() { - SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE); - } - - void SetConnectionType(ConnectionType type) { - connection_type_ = type; - NotifyObserversOfNetworkChange(type); - base::RunLoop().RunUntilIdle(); - } - - virtual ~FakeNetworkChangeNotifier() {} - - private: - ConnectionType connection_type_; - DISALLOW_COPY_AND_ASSIGN(FakeNetworkChangeNotifier); -}; - // Helper class that monitors app windows to wait for a window to appear. class ShellWindowObserver : public apps::ShellWindowRegistry::Observer { public: @@ -262,6 +253,11 @@ class KioskTest : public InProcessBrowserTest { virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { host_resolver()->AddRule("*", "127.0.0.1"); + + network_portal_detector_ = new NetworkPortalDetectorTestImpl(); + NetworkPortalDetector::InitializeForTesting(network_portal_detector_); + network_portal_detector_->SetDefaultNetworkPathForTesting( + kStubEthernetServicePath); } virtual void SetUpOnMainThread() OVERRIDE { @@ -270,10 +266,6 @@ class KioskTest : public InProcessBrowserTest { } virtual void CleanUpOnMainThread() OVERRIDE { - // We need to clean up these objects in this specific order. - fake_network_notifier_.reset(NULL); - disable_network_notifier_.reset(NULL); - AppLaunchController::SetNetworkTimeoutCallbackForTesting(NULL); AppLaunchSigninScreen::SetUserManagerForTesting(NULL); @@ -331,7 +323,7 @@ class KioskTest : public InProcessBrowserTest { KioskAppManager::Get()->SetAutoLaunchApp(kTestKioskApp); } - void StartAppLaunchFromLoginScreen(bool has_connectivity) { + void StartAppLaunchFromLoginScreen(const base::Closure& network_setup_cb) { EnableConsumerKioskMode(); // Start UI, find menu entry for this app and launch it. @@ -352,8 +344,8 @@ class KioskTest : public InProcessBrowserTest { ReloadKioskApps(); apps_loaded_signal.Wait(); - if (!has_connectivity) - SimulateNetworkOffline(); + if (!network_setup_cb.is_null()) + network_setup_cb.Run(); GetLoginUI()->CallJavascriptFunction( "login.AppsMenuButton.runAppForTesting", @@ -410,15 +402,43 @@ class KioskTest : public InProcessBrowserTest { } void SimulateNetworkOffline() { - disable_network_notifier_.reset( - new net::NetworkChangeNotifier::DisableForTest); + NetworkPortalDetector::CaptivePortalState offline_state; + offline_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE; + network_portal_detector_->SetDetectionResultsForTesting( + kStubEthernetServicePath, offline_state); + network_portal_detector_->NotifyObserversForTesting(); + } - fake_network_notifier_.reset(new FakeNetworkChangeNotifier); + base::Closure SimulateNetworkOfflineClosure() { + return base::Bind(&KioskTest::SimulateNetworkOffline, + base::Unretained(this)); } void SimulateNetworkOnline() { - if (fake_network_notifier_.get()) - fake_network_notifier_->GoOnline(); + NetworkPortalDetector::CaptivePortalState online_state; + online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE; + online_state.response_code = 204; + network_portal_detector_->SetDetectionResultsForTesting( + kStubEthernetServicePath, online_state); + network_portal_detector_->NotifyObserversForTesting(); + } + + base::Closure SimulateNetworkOnlineClosure() { + return base::Bind(&KioskTest::SimulateNetworkOnline, + base::Unretained(this)); + } + + void SimulateNetworkPortal() { + NetworkPortalDetector::CaptivePortalState portal_state; + portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL; + network_portal_detector_->SetDetectionResultsForTesting( + kStubEthernetServicePath, portal_state); + network_portal_detector_->NotifyObserversForTesting(); + } + + base::Closure SimulateNetworkPortalClosure() { + return base::Bind(&KioskTest::SimulateNetworkPortal, + base::Unretained(this)); } void WaitForAppLaunchNetworkTimeout() { @@ -491,23 +511,21 @@ class KioskTest : public InProcessBrowserTest { } FakeGaia fake_gaia_; - scoped_ptr<net::NetworkChangeNotifier::DisableForTest> - disable_network_notifier_; - scoped_ptr<FakeNetworkChangeNotifier> fake_network_notifier_; scoped_ptr<MockUserManager> mock_user_manager_; + NetworkPortalDetectorTestImpl* network_portal_detector_; }; IN_PROC_BROWSER_TEST_F(KioskTest, InstallAndLaunchApp) { - StartAppLaunchFromLoginScreen(true); + StartAppLaunchFromLoginScreen(SimulateNetworkOnlineClosure()); WaitForAppLaunchSuccess(); } IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkDown) { - // Mock network could be configured. - ScopedCanConfigureNetwork can_configure_network(true); + // Mock network could be configured with owner's password. + ScopedCanConfigureNetwork can_configure_network(true, true); // Start app launch and wait for network connectivity timeout. - StartAppLaunchFromLoginScreen(false); + StartAppLaunchFromLoginScreen(SimulateNetworkOfflineClosure()); OobeScreenWaiter splash_waiter(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH); splash_waiter.Wait(); WaitForAppLaunchNetworkTimeout(); @@ -540,10 +558,10 @@ IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkDown) { IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkDownConfigureNotAllowed) { // Mock network could not be configured. - ScopedCanConfigureNetwork can_configure_network(false); + ScopedCanConfigureNetwork can_configure_network(false, true); // Start app launch and wait for network connectivity timeout. - StartAppLaunchFromLoginScreen(false); + StartAppLaunchFromLoginScreen(SimulateNetworkOfflineClosure()); OobeScreenWaiter splash_waiter(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH); splash_waiter.Wait(); WaitForAppLaunchNetworkTimeout(); @@ -555,8 +573,26 @@ IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkDownConfigureNotAllowed) { WaitForAppLaunchSuccess(); } +IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkPortal) { + // Mock network could be configured without the owner password. + ScopedCanConfigureNetwork can_configure_network(true, false); + + // Start app launch with network portal state. + StartAppLaunchFromLoginScreen(SimulateNetworkPortalClosure()); + OobeScreenWaiter(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH) + .WaitNoAssertCurrentScreen(); + WaitForAppLaunchNetworkTimeout(); + + // Network error should show up automatically since this test does not + // require owner auth to configure network. + OobeScreenWaiter(OobeDisplay::SCREEN_ERROR_MESSAGE).Wait(); + + ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog()); + WaitForAppLaunchSuccess(); +} + IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppUserCancel) { - StartAppLaunchFromLoginScreen(false); + StartAppLaunchFromLoginScreen(SimulateNetworkOfflineClosure()); OobeScreenWaiter splash_waiter(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH); splash_waiter.Wait(); diff --git a/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h b/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h index 83ad878..2547466 100644 --- a/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h +++ b/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h @@ -23,9 +23,16 @@ class AppLaunchSplashScreenActor { class Delegate { public: + // Invoked when the configure network control is clicked. virtual void OnConfigureNetwork() = 0; + + // Invoked when the app launch bailout shortcut key is pressed. virtual void OnCancelAppLaunch() = 0; + // Invoked when network state is changed. |online| is true if the device + // is connected to the Internet. + virtual void OnNetworkStateChanged(bool online) = 0; + protected: virtual ~Delegate() {} }; @@ -47,8 +54,11 @@ class AppLaunchSplashScreenActor { // Set the current app launch state. virtual void UpdateAppLaunchState(AppLaunchState state) = 0; - // Sets whether continue control is enabled. + // Sets whether configure network control is visible. virtual void ToggleNetworkConfig(bool visible) = 0; + + // Shows the network error and configure UI. + virtual void ShowNetworkConfigureUI() = 0; }; } // namespace chromeos diff --git a/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc b/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc index 456bd4c..1e2b44b 100644 --- a/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc +++ b/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc @@ -22,16 +22,20 @@ OobeScreenWaiter::~OobeScreenWaiter() { } void OobeScreenWaiter::Wait() { - if (GetOobeUI()->current_screen() == expected_screen_) { + WaitNoAssertCurrentScreen(); + + ASSERT_EQ(expected_screen_, GetOobeUI()->current_screen()); +} + +void OobeScreenWaiter::WaitNoAssertCurrentScreen() { + if (GetOobeUI()->current_screen() == expected_screen_) return; - } waiting_for_screen_ = true; GetOobeUI()->AddObserver(this); runner_ = new content::MessageLoopRunner; runner_->Run(); - ASSERT_EQ(expected_screen_, GetOobeUI()->current_screen()); ASSERT_FALSE(waiting_for_screen_); } diff --git a/chrome/browser/chromeos/login/test/oobe_screen_waiter.h b/chrome/browser/chromeos/login/test/oobe_screen_waiter.h index 4704f37..8df9b8b 100644 --- a/chrome/browser/chromeos/login/test/oobe_screen_waiter.h +++ b/chrome/browser/chromeos/login/test/oobe_screen_waiter.h @@ -21,8 +21,14 @@ class OobeScreenWaiter : public OobeUI::Observer { explicit OobeScreenWaiter(OobeDisplay::Screen expected_screen); virtual ~OobeScreenWaiter(); + // Run message loop to wait for the expected_screen. void Wait(); + // Similar to Wait() but does not assert the current screen is + // expected_screen on exit. Use this when there are multiple screen changes + // during the wait and the screen to be waited is not the final one. + void WaitNoAssertCurrentScreen(); + // OobeUI::Observer implementation: virtual void OnCurrentScreenChanged( OobeDisplay::Screen current_screen, diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc index acf85b7..ea40489 100644 --- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc @@ -182,6 +182,14 @@ void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy, container.enable_auto_login_bailout()), NULL); } + if (container.has_prompt_for_network_when_offline()) { + policies->Set(key::kDeviceLocalAccountPromptForNetworkWhenOffline, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, + Value::CreateBooleanValue( + container.prompt_for_network_when_offline()), + NULL); + } } if (policy.has_supervised_users_settings()) { diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc index 6ed8114..439c271b 100644 --- a/chrome/browser/chromeos/settings/device_settings_provider.cc +++ b/chrome/browser/chromeos/settings/device_settings_provider.cc @@ -51,6 +51,7 @@ const char* kKnownSettings[] = { kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, kAccountsPrefDeviceLocalAccountAutoLoginDelay, kAccountsPrefDeviceLocalAccountAutoLoginId, + kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline, kAccountsPrefEphemeralUsersEnabled, kAccountsPrefShowUserNamesOnSignIn, kAccountsPrefSupervisedUsersEnabled, @@ -307,6 +308,15 @@ void DeviceSettingsProvider::SetInPolicy() { device_local_accounts->set_enable_auto_login_bailout(enabled); else NOTREACHED(); + } else if (prop == + kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline) { + em::DeviceLocalAccountsProto* device_local_accounts = + device_settings_.mutable_device_local_accounts(); + bool should_prompt; + if (value->GetAsBoolean(&should_prompt)) + device_local_accounts->set_prompt_for_network_when_offline(should_prompt); + else + NOTREACHED(); } else if (prop == kSignedDataRoamingEnabled) { em::DataRoamingEnabledProto* roam = device_settings_.mutable_data_roaming_enabled(); @@ -554,6 +564,9 @@ void DeviceSettingsProvider::DecodeLoginPolicies( new_values_cache->SetBoolean( kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, policy.device_local_accounts().enable_auto_login_bailout()); + new_values_cache->SetBoolean( + kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline, + policy.device_local_accounts().prompt_for_network_when_offline()); if (policy.has_start_up_flags()) { base::ListValue* list = new base::ListValue(); @@ -816,9 +829,9 @@ void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file, migration_values_.SetValue(kStatsReportingPref, base::Value::CreateBooleanValue(new_value)); AttemptMigration(); - LOG(INFO) << "No metrics policy set will revert to checking " - << "consent file which is " - << (new_value ? "on." : "off."); + VLOG(1) << "No metrics policy set will revert to checking " + << "consent file which is " + << (new_value ? "on." : "off."); UMA_HISTOGRAM_COUNTS("DeviceSettings.MetricsMigrated", 1); } VLOG(1) << "Metrics policy is being set to : " << new_value diff --git a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto index 911866b..b841f1f 100644 --- a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto +++ b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto @@ -313,9 +313,19 @@ message DeviceLocalAccountsProto { // Whether the keyboard shortcut to prevent zero-delay auto-login should be // enabled or not. If this keyboard shortcut is engaged, the auto-login will - // be delayed by 3 minutes so administrators can log in or make configuration + // be delayed by 3 seconds so administrators can log in or make configuration // changes. optional bool enable_auto_login_bailout = 4 [default = true]; + + // Whether network configuration should be offered or not when the device + // does not have access to the Internet. If the policy is omitted or set to + // true, the network configuration will be offered. Otherwise, only an error + // message is displayed. + // Note: If both this policy and enable_auto_login_bailout policy above is + // set to false, there are chances that the device might become totally + // unusable when there is no Internet access and has to go through the + // recovery process. + optional bool prompt_for_network_when_offline = 5 [default = true]; } message AllowRedeemChromeOsRegistrationOffersProto { diff --git a/chrome/browser/resources/chromeos/login/screen_error_message.css b/chrome/browser/resources/chromeos/login/screen_error_message.css index 73ec409..3160803 100644 --- a/chrome/browser/resources/chromeos/login/screen_error_message.css +++ b/chrome/browser/resources/chromeos/login/screen_error_message.css @@ -93,3 +93,7 @@ .offline-network-list-label { -webkit-margin-end: 10px; } + +.button-spacer { + -webkit-box-flex: 1; +} diff --git a/chrome/browser/resources/chromeos/login/screen_error_message.js b/chrome/browser/resources/chromeos/login/screen_error_message.js index 2c51904..039208c 100644 --- a/chrome/browser/resources/chromeos/login/screen_error_message.js +++ b/chrome/browser/resources/chromeos/login/screen_error_message.js @@ -165,6 +165,20 @@ login.createScreen('ErrorMessageScreen', 'error-message', function() { get buttons() { var buttons = []; + var rebootButton = this.ownerDocument.createElement('button'); + rebootButton.textContent = loadTimeData.getString('rebootButton'); + rebootButton.classList.add('show-with-ui-state-kiosk-mode'); + rebootButton.addEventListener('click', function(e) { + chrome.send('rebootButtonClicked'); + e.stopPropagation(); + }); + buttons.push(rebootButton); + + var spacer = this.ownerDocument.createElement('div'); + spacer.classList.add('button-spacer'); + spacer.classList.add('show-with-ui-state-kiosk-mode'); + buttons.push(spacer); + var powerwashButton = this.ownerDocument.createElement('button'); powerwashButton.id = 'error-message-restart-and-powerwash-button'; powerwashButton.textContent = diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc index 5542049..e95fa2e 100644 --- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc @@ -5,7 +5,10 @@ #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" +#include "chrome/browser/chromeos/login/screens/error_screen_actor.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" #include "grit/browser_resources.h" #include "grit/chrome_unscaled_resources.h" #include "grit/chromium_strings.h" @@ -18,18 +21,34 @@ namespace { const char kJsScreenPath[] = "login.AppLaunchSplashScreen"; +// Returns network name by service path. +std::string GetNetworkName(const std::string& service_path) { + const chromeos::NetworkState* network = + chromeos::NetworkHandler::Get()->network_state_handler()->GetNetworkState( + service_path); + if (!network) + return std::string(); + return network->name(); +} + } // namespace namespace chromeos { -AppLaunchSplashScreenHandler::AppLaunchSplashScreenHandler() +AppLaunchSplashScreenHandler::AppLaunchSplashScreenHandler( + const scoped_refptr<NetworkStateInformer>& network_state_informer, + ErrorScreenActor* error_screen_actor) : BaseScreenHandler(kJsScreenPath), delegate_(NULL), show_on_init_(false), - state_(APP_LAUNCH_STATE_LOADING_AUTH_FILE) { + state_(APP_LAUNCH_STATE_LOADING_AUTH_FILE), + network_state_informer_(network_state_informer), + error_screen_actor_(error_screen_actor) { + network_state_informer_->AddObserver(this); } AppLaunchSplashScreenHandler::~AppLaunchSplashScreenHandler() { + network_state_informer_->RemoveObserver(this); } void AppLaunchSplashScreenHandler::DeclareLocalizedValues( @@ -103,6 +122,7 @@ void AppLaunchSplashScreenHandler::UpdateAppLaunchState(AppLaunchState state) { SetLaunchText( l10n_util::GetStringUTF8(GetProgressMessageFromState(state_))); } + UpdateState(ErrorScreenActor::ERROR_REASON_UPDATE); } void AppLaunchSplashScreenHandler::SetDelegate( @@ -110,6 +130,71 @@ void AppLaunchSplashScreenHandler::SetDelegate( delegate_ = delegate; } +void AppLaunchSplashScreenHandler::ShowNetworkConfigureUI() { + NetworkStateInformer::State state = network_state_informer_->state(); + if (state == NetworkStateInformer::ONLINE) { + delegate_->OnNetworkStateChanged(true); + return; + } + + const std::string network_path = network_state_informer_->network_path(); + const std::string network_name = GetNetworkName(network_path); + + error_screen_actor_->SetUIState(ErrorScreen::UI_STATE_KIOSK_MODE); + error_screen_actor_->AllowGuestSignin(false); + error_screen_actor_->AllowOfflineLogin(false); + + switch (state) { + case NetworkStateInformer::CAPTIVE_PORTAL: { + error_screen_actor_->SetErrorState( + ErrorScreen::ERROR_STATE_PORTAL, network_name); + error_screen_actor_->FixCaptivePortal(); + + break; + } + case NetworkStateInformer::PROXY_AUTH_REQUIRED: { + error_screen_actor_->SetErrorState( + ErrorScreen::ERROR_STATE_PROXY, network_name); + break; + } + case NetworkStateInformer::OFFLINE: { + error_screen_actor_->SetErrorState( + ErrorScreen::ERROR_STATE_OFFLINE, network_name); + break; + } + default: + error_screen_actor_->SetErrorState( + ErrorScreen::ERROR_STATE_OFFLINE, network_name); + NOTREACHED(); + break; + }; + + OobeUI::Screen screen = OobeUI::SCREEN_UNKNOWN; + OobeUI* oobe_ui = static_cast<OobeUI*>(web_ui()->GetController()); + if (oobe_ui) + screen = oobe_ui->current_screen(); + + if (screen != OobeUI::SCREEN_ERROR_MESSAGE) + error_screen_actor_->Show(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH, NULL); +} + +void AppLaunchSplashScreenHandler::OnNetworkReady() { + // Purposely leave blank because the online case is handled in UpdateState + // call below. +} + +void AppLaunchSplashScreenHandler::UpdateState( + ErrorScreenActor::ErrorReason reason) { + if (!delegate_ || + (state_ != APP_LAUNCH_STATE_PREPARING_NETWORK && + state_ != APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT)) { + return; + } + + NetworkStateInformer::State state = network_state_informer_->state(); + delegate_->OnNetworkStateChanged(state == NetworkStateInformer::ONLINE); +} + void AppLaunchSplashScreenHandler::PopulateAppInfo( base::DictionaryValue* out_info) { KioskAppManager::App app; diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h index 72cc4b7..f2c10b5 100644 --- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h @@ -10,14 +10,21 @@ #include "chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h" #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h" namespace chromeos { +class ErrorScreenActor; + // A class that handles the WebUI hooks for the app launch splash screen. -class AppLaunchSplashScreenHandler : public BaseScreenHandler, - public AppLaunchSplashScreenActor { +class AppLaunchSplashScreenHandler + : public BaseScreenHandler, + public AppLaunchSplashScreenActor, + public NetworkStateInformer::NetworkStateInformerObserver { public: - AppLaunchSplashScreenHandler(); + AppLaunchSplashScreenHandler( + const scoped_refptr<NetworkStateInformer>& network_state_informer, + ErrorScreenActor* error_screen_actor); virtual ~AppLaunchSplashScreenHandler(); // BaseScreenHandler implementation: @@ -35,6 +42,11 @@ class AppLaunchSplashScreenHandler : public BaseScreenHandler, virtual void UpdateAppLaunchState(AppLaunchState state) OVERRIDE; virtual void SetDelegate( AppLaunchSplashScreenHandler::Delegate* delegate) OVERRIDE; + virtual void ShowNetworkConfigureUI() OVERRIDE; + + // NetworkStateInformer::NetworkStateInformerObserver implementation: + virtual void OnNetworkReady() OVERRIDE; + virtual void UpdateState(ErrorScreenActor::ErrorReason reason) OVERRIDE; private: void PopulateAppInfo(base::DictionaryValue* out_info); @@ -48,6 +60,9 @@ class AppLaunchSplashScreenHandler : public BaseScreenHandler, std::string app_id_; AppLaunchState state_; + scoped_refptr<NetworkStateInformer> network_state_informer_; + ErrorScreenActor* error_screen_actor_; + DISALLOW_COPY_AND_ASSIGN(AppLaunchSplashScreenHandler); }; diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc index 978a67a..8d6f25a 100644 --- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc @@ -15,6 +15,7 @@ #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h" #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h" #include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" #include "chromeos/dbus/session_manager_client.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -140,6 +141,10 @@ void ErrorScreenHandler::HandleLocalStateErrorPowerwashButtonClicked() { StartDeviceWipe(); } +void ErrorScreenHandler::HandleRebootButtonClicked() { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); +} + void ErrorScreenHandler::RegisterMessages() { AddCallback("showCaptivePortal", &ErrorScreenHandler::HandleShowCaptivePortal); @@ -147,6 +152,8 @@ void ErrorScreenHandler::RegisterMessages() { &ErrorScreenHandler::HandleHideCaptivePortal); AddCallback("localStateErrorPowerwashButtonClicked", &ErrorScreenHandler::HandleLocalStateErrorPowerwashButtonClicked); + AddCallback("rebootButtonClicked", + &ErrorScreenHandler::HandleRebootButtonClicked); } void ErrorScreenHandler::DeclareLocalizedValues( @@ -168,6 +175,7 @@ void ErrorScreenHandler::DeclareLocalizedValues( builder->Add("localStateErrorText1", IDS_LOCAL_STATE_ERROR_TEXT_1); builder->Add("localStateErrorPowerwashButton", IDS_LOCAL_STATE_ERROR_POWERWASH_BUTTON); + builder->Add("rebootButton", IDS_RELAUNCH_BUTTON); } void ErrorScreenHandler::Initialize() { diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h index 88eed50..8a53aae 100644 --- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h @@ -53,6 +53,7 @@ class ErrorScreenHandler : public BaseScreenHandler, void HandleShowCaptivePortal(); void HandleHideCaptivePortal(); void HandleLocalStateErrorPowerwashButtonClicked(); + void HandleRebootButtonClicked(); // WebUIMessageHandler implementation: virtual void RegisterMessages() OVERRIDE; diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc index 35c60d3..f7adbe9 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc @@ -252,7 +252,8 @@ OobeUI::OobeUI(content::WebUI* web_ui, const GURL& url) AddScreenHandler(signin_screen_handler_); AppLaunchSplashScreenHandler* app_launch_splash_screen_handler = - new AppLaunchSplashScreenHandler(); + new AppLaunchSplashScreenHandler(network_state_informer_, + error_screen_handler_); AddScreenHandler(app_launch_splash_screen_handler); app_launch_splash_screen_actor_ = app_launch_splash_screen_handler; diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 03c335a..925e7c1 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json @@ -2076,6 +2076,9 @@ "DeviceLocalAccountAutoLoginBailoutEnabled": { }, + "DeviceLocalAccountPromptForNetworkWhenOffline": { + }, + "DeviceLoginScreenPowerManagement": { }, diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc index fbc30a3..d28c01d 100644 --- a/chromeos/settings/cros_settings_names.cc +++ b/chromeos/settings/cros_settings_names.cc @@ -30,6 +30,8 @@ const char kAccountsPrefDeviceLocalAccountAutoLoginDelay[] = "cros.accounts.deviceLocalAccountAutoLoginDelay"; const char kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled[] = "cros.accounts.deviceLocalAccountAutoLoginBailoutEnabled"; +const char kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline[] = + "cros.accounts.deviceLocalAccountPromptForNetworkWhenOffline"; const char kAccountsPrefSupervisedUsersEnabled[] = "cros.accounts.supervisedUsersEnabled"; diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h index ffaf6f4..854c6bc 100644 --- a/chromeos/settings/cros_settings_names.h +++ b/chromeos/settings/cros_settings_names.h @@ -27,6 +27,8 @@ CHROMEOS_EXPORT extern const char kAccountsPrefDeviceLocalAccountAutoLoginDelay[]; CHROMEOS_EXPORT extern const char kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled[]; +CHROMEOS_EXPORT extern const char + kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline[]; CHROMEOS_EXPORT extern const char kAccountsPrefSupervisedUsersEnabled[]; CHROMEOS_EXPORT extern const char kSignedDataRoamingEnabled[]; diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 3f00da2..c855889 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -22997,6 +22997,7 @@ other types of suffix sets. session"/> <int value="248" label="Report device users"/> <int value="249" label="User avatar image"/> + <int value="250" label="Enable network configuration prompt when offline"/> </enum> <enum name="EnterprisePolicyInvalidations" type="int"> |