1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
6
7#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
8#include "chrome/browser/chromeos/login/screens/error_screen_actor.h"
9#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
10#include "chrome/grit/chromium_strings.h"
11#include "chrome/grit/generated_resources.h"
12#include "chromeos/network/network_state.h"
13#include "chromeos/network/network_state_handler.h"
14#include "grit/chrome_unscaled_resources.h"
15#include "ui/base/l10n/l10n_util.h"
16#include "ui/base/resource/resource_bundle.h"
17#include "ui/base/webui/web_ui_util.h"
18
19namespace {
20
21const char kJsScreenPath[] = "login.AppLaunchSplashScreen";
22
23// Returns network name by service path.
24std::string GetNetworkName(const std::string& service_path) {
25  const chromeos::NetworkState* network =
26      chromeos::NetworkHandler::Get()->network_state_handler()->GetNetworkState(
27          service_path);
28  if (!network)
29    return std::string();
30  return network->name();
31}
32
33}  // namespace
34
35namespace chromeos {
36
37AppLaunchSplashScreenHandler::AppLaunchSplashScreenHandler(
38      const scoped_refptr<NetworkStateInformer>& network_state_informer,
39      ErrorScreenActor* error_screen_actor)
40    : BaseScreenHandler(kJsScreenPath),
41      delegate_(NULL),
42      show_on_init_(false),
43      state_(APP_LAUNCH_STATE_LOADING_AUTH_FILE),
44      network_state_informer_(network_state_informer),
45      error_screen_actor_(error_screen_actor),
46      online_state_(false),
47      network_config_done_(false),
48      network_config_requested_(false) {
49  network_state_informer_->AddObserver(this);
50}
51
52AppLaunchSplashScreenHandler::~AppLaunchSplashScreenHandler() {
53  network_state_informer_->RemoveObserver(this);
54}
55
56void AppLaunchSplashScreenHandler::DeclareLocalizedValues(
57    LocalizedValuesBuilder* builder) {
58
59  builder->Add("appStartMessage", IDS_APP_START_NETWORK_WAIT_MESSAGE);
60  builder->Add("configureNetwork", IDS_APP_START_CONFIGURE_NETWORK);
61
62  const base::string16 product_os_name =
63      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
64  builder->Add(
65      "shortcutInfo",
66      l10n_util::GetStringFUTF16(IDS_APP_START_BAILOUT_SHORTCUT_FORMAT,
67                                 product_os_name));
68
69  builder->Add(
70      "productName",
71      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME));
72}
73
74void AppLaunchSplashScreenHandler::Initialize() {
75  if (show_on_init_) {
76    show_on_init_ = false;
77    Show(app_id_);
78  }
79}
80
81void AppLaunchSplashScreenHandler::Show(const std::string& app_id) {
82  app_id_ = app_id;
83  if (!page_is_ready()) {
84    show_on_init_ = true;
85    return;
86  }
87
88  base::DictionaryValue data;
89  data.SetBoolean("shortcutEnabled",
90                  !KioskAppManager::Get()->GetDisableBailoutShortcut());
91
92  // |data| will take ownership of |app_info|.
93  base::DictionaryValue *app_info = new base::DictionaryValue();
94  PopulateAppInfo(app_info);
95  data.Set("appInfo", app_info);
96
97  SetLaunchText(l10n_util::GetStringUTF8(GetProgressMessageFromState(state_)));
98  ShowScreen(OobeUI::kScreenAppLaunchSplash, &data);
99}
100
101void AppLaunchSplashScreenHandler::RegisterMessages() {
102  AddCallback("configureNetwork",
103              &AppLaunchSplashScreenHandler::HandleConfigureNetwork);
104  AddCallback("cancelAppLaunch",
105              &AppLaunchSplashScreenHandler::HandleCancelAppLaunch);
106  AddCallback("continueAppLaunch",
107              &AppLaunchSplashScreenHandler::HandleContinueAppLaunch);
108  AddCallback("networkConfigRequest",
109              &AppLaunchSplashScreenHandler::HandleNetworkConfigRequested);
110}
111
112void AppLaunchSplashScreenHandler::PrepareToShow() {
113}
114
115void AppLaunchSplashScreenHandler::Hide() {
116}
117
118void AppLaunchSplashScreenHandler::ToggleNetworkConfig(bool visible) {
119  CallJS("toggleNetworkConfig", visible);
120}
121
122void AppLaunchSplashScreenHandler::UpdateAppLaunchState(AppLaunchState state) {
123  if (state == state_)
124    return;
125
126  state_ = state;
127  if (page_is_ready()) {
128    SetLaunchText(
129        l10n_util::GetStringUTF8(GetProgressMessageFromState(state_)));
130  }
131  UpdateState(ErrorScreenActor::ERROR_REASON_UPDATE);
132}
133
134void AppLaunchSplashScreenHandler::SetDelegate(
135    AppLaunchSplashScreenHandler::Delegate* delegate) {
136  delegate_ = delegate;
137}
138
139void AppLaunchSplashScreenHandler::ShowNetworkConfigureUI() {
140  NetworkStateInformer::State state = network_state_informer_->state();
141  if (state == NetworkStateInformer::ONLINE) {
142    online_state_ = true;
143    if (!network_config_requested_) {
144      delegate_->OnNetworkStateChanged(true);
145      return;
146    }
147  }
148
149  const std::string network_path = network_state_informer_->network_path();
150  const std::string network_name = GetNetworkName(network_path);
151
152  error_screen_actor_->SetUIState(ErrorScreen::UI_STATE_KIOSK_MODE);
153  error_screen_actor_->AllowGuestSignin(false);
154  error_screen_actor_->AllowOfflineLogin(false);
155
156  switch (state) {
157    case NetworkStateInformer::CAPTIVE_PORTAL: {
158      error_screen_actor_->SetErrorState(
159          ErrorScreen::ERROR_STATE_PORTAL, network_name);
160      error_screen_actor_->FixCaptivePortal();
161
162      break;
163    }
164    case NetworkStateInformer::PROXY_AUTH_REQUIRED: {
165      error_screen_actor_->SetErrorState(
166          ErrorScreen::ERROR_STATE_PROXY, network_name);
167      break;
168    }
169    case NetworkStateInformer::OFFLINE: {
170      error_screen_actor_->SetErrorState(
171          ErrorScreen::ERROR_STATE_OFFLINE, network_name);
172      break;
173    }
174    case NetworkStateInformer::ONLINE: {
175      error_screen_actor_->SetErrorState(
176          ErrorScreen::ERROR_STATE_KIOSK_ONLINE, network_name);
177      break;
178    }
179    default:
180      error_screen_actor_->SetErrorState(
181          ErrorScreen::ERROR_STATE_OFFLINE, network_name);
182      NOTREACHED();
183      break;
184  }
185
186  OobeUI::Screen screen = OobeUI::SCREEN_UNKNOWN;
187  OobeUI* oobe_ui = static_cast<OobeUI*>(web_ui()->GetController());
188  if (oobe_ui)
189    screen = oobe_ui->current_screen();
190
191  if (screen != OobeUI::SCREEN_ERROR_MESSAGE)
192    error_screen_actor_->Show(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH, NULL);
193}
194
195bool AppLaunchSplashScreenHandler::IsNetworkReady() {
196  return network_state_informer_->state() == NetworkStateInformer::ONLINE;
197}
198
199void AppLaunchSplashScreenHandler::OnNetworkReady() {
200  // Purposely leave blank because the online case is handled in UpdateState
201  // call below.
202}
203
204void AppLaunchSplashScreenHandler::UpdateState(
205    ErrorScreenActor::ErrorReason reason) {
206  if (!delegate_ ||
207      (state_ != APP_LAUNCH_STATE_PREPARING_NETWORK &&
208       state_ != APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT)) {
209    return;
210  }
211
212  bool new_online_state =
213      network_state_informer_->state() == NetworkStateInformer::ONLINE;
214  delegate_->OnNetworkStateChanged(new_online_state);
215
216  online_state_ = new_online_state;
217}
218
219void AppLaunchSplashScreenHandler::PopulateAppInfo(
220    base::DictionaryValue* out_info) {
221  KioskAppManager::App app;
222  KioskAppManager::Get()->GetApp(app_id_, &app);
223
224  if (app.name.empty())
225    app.name = l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME);
226
227  if (app.icon.isNull()) {
228    app.icon = *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
229        IDR_PRODUCT_LOGO_128);
230  }
231
232  out_info->SetString("name", app.name);
233  out_info->SetString("iconURL", webui::GetBitmapDataUrl(*app.icon.bitmap()));
234}
235
236void AppLaunchSplashScreenHandler::SetLaunchText(const std::string& text) {
237  CallJS("updateMessage", text);
238}
239
240int AppLaunchSplashScreenHandler::GetProgressMessageFromState(
241    AppLaunchState state) {
242  switch (state) {
243    case APP_LAUNCH_STATE_LOADING_AUTH_FILE:
244    case APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE:
245      // TODO(zelidrag): Add better string for this one than "Please wait..."
246      return IDS_SYNC_SETUP_SPINNER_TITLE;
247    case APP_LAUNCH_STATE_PREPARING_NETWORK:
248      return IDS_APP_START_NETWORK_WAIT_MESSAGE;
249    case APP_LAUNCH_STATE_INSTALLING_APPLICATION:
250      return IDS_APP_START_APP_WAIT_MESSAGE;
251    case APP_LAUNCH_STATE_WAITING_APP_WINDOW:
252      return IDS_APP_START_WAIT_FOR_APP_WINDOW_MESSAGE;
253    case APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT:
254      return IDS_APP_START_NETWORK_WAIT_TIMEOUT_MESSAGE;
255  }
256  return IDS_APP_START_NETWORK_WAIT_MESSAGE;
257}
258
259void AppLaunchSplashScreenHandler::HandleConfigureNetwork() {
260  if (delegate_)
261    delegate_->OnConfigureNetwork();
262  else
263    LOG(WARNING) << "No delegate set to handle network configuration.";
264}
265
266void AppLaunchSplashScreenHandler::HandleCancelAppLaunch() {
267  if (delegate_)
268    delegate_->OnCancelAppLaunch();
269  else
270    LOG(WARNING) << "No delegate set to handle cancel app launch";
271}
272
273void AppLaunchSplashScreenHandler::HandleNetworkConfigRequested() {
274  if (!delegate_ || network_config_done_)
275    return;
276
277  network_config_requested_ = true;
278  delegate_->OnNetworkConfigRequested(true);
279}
280
281void AppLaunchSplashScreenHandler::HandleContinueAppLaunch() {
282  DCHECK(online_state_);
283  if (delegate_ && online_state_) {
284    network_config_requested_ = false;
285    network_config_done_ = true;
286    delegate_->OnNetworkConfigRequested(false);
287    Show(app_id_);
288  }
289}
290
291}  // namespace chromeos
292