blob: 99125e9e87fc7acd4bdcecb08fd2a2b6bdd32d94 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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/ui/webui/chromeos/imageburner/imageburner_ui.h"
6
7#include "base/bind.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00008#include "base/files/file_path.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +00009#include "base/i18n/rtl.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010010#include "base/strings/string16.h"
11#include "base/strings/utf_string_conversions.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000012#include "base/values.h"
13#include "chrome/browser/chromeos/imageburner/burn_controller.h"
14#include "chrome/browser/profiles/profile.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000015#include "chrome/common/url_constants.h"
16#include "content/public/browser/web_ui.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000017#include "content/public/browser/web_ui_data_source.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000018#include "content/public/browser/web_ui_message_handler.h"
19#include "grit/browser_resources.h"
20#include "grit/generated_resources.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000021#include "ui/base/l10n/l10n_util.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010022#include "ui/base/l10n/time_format.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000023#include "ui/base/text/bytes_formatting.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010024#include "url/gurl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000025
26namespace chromeos {
27namespace imageburner {
28
29namespace {
30
31const char kPropertyDevicePath[] = "devicePath";
32const char kPropertyFilePath[] = "filePath";
33const char kPropertyLabel[] = "label";
34const char kPropertyPath[] = "path";
35const char kPropertyDeviceType[] = "type";
36
37// Link displayed on imageburner ui.
38const char kMoreInfoLink[] =
39 "http://www.chromium.org/chromium-os/chromiumos-design-docs/recovery-mode";
40
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000041content::WebUIDataSource* CreateImageburnerUIHTMLSource() {
42 content::WebUIDataSource* source =
43 content::WebUIDataSource::Create(chrome::kChromeUIImageBurnerHost);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000044
45 source->AddLocalizedString("headerTitle", IDS_IMAGEBURN_HEADER_TITLE);
46 source->AddLocalizedString("headerDescription",
47 IDS_IMAGEBURN_HEADER_DESCRIPTION);
48 source->AddLocalizedString("headerLink", IDS_IMAGEBURN_HEADER_LINK);
49 source->AddLocalizedString("statusDevicesNone",
50 IDS_IMAGEBURN_NO_DEVICES_STATUS);
51 source->AddLocalizedString("warningDevicesNone",
52 IDS_IMAGEBURN_NO_DEVICES_WARNING);
53 source->AddLocalizedString("statusDevicesMultiple",
54 IDS_IMAGEBURN_MUL_DEVICES_STATUS);
55 source->AddLocalizedString("statusDeviceUSB",
56 IDS_IMAGEBURN_USB_DEVICE_STATUS);
57 source->AddLocalizedString("statusDeviceSD",
58 IDS_IMAGEBURN_SD_DEVICE_STATUS);
59 source->AddLocalizedString("warningDevices",
60 IDS_IMAGEBURN_DEVICES_WARNING);
61 source->AddLocalizedString("statusNoConnection",
62 IDS_IMAGEBURN_NO_CONNECTION_STATUS);
63 source->AddLocalizedString("warningNoConnection",
64 IDS_IMAGEBURN_NO_CONNECTION_WARNING);
65 source->AddLocalizedString("statusNoSpace",
66 IDS_IMAGEBURN_INSUFFICIENT_SPACE_STATUS);
67 source->AddLocalizedString("warningNoSpace",
68 IDS_IMAGEBURN_INSUFFICIENT_SPACE_WARNING);
69 source->AddLocalizedString("statusDownloading",
70 IDS_IMAGEBURN_DOWNLOADING_STATUS);
71 source->AddLocalizedString("statusUnzip", IDS_IMAGEBURN_UNZIP_STATUS);
72 source->AddLocalizedString("statusBurn", IDS_IMAGEBURN_BURN_STATUS);
73 source->AddLocalizedString("statusError", IDS_IMAGEBURN_ERROR_STATUS);
74 source->AddLocalizedString("statusSuccess", IDS_IMAGEBURN_SUCCESS_STATUS);
75 source->AddLocalizedString("warningSuccess", IDS_IMAGEBURN_SUCCESS_DESC);
76 source->AddLocalizedString("title", IDS_IMAGEBURN_PAGE_TITLE);
77 source->AddLocalizedString("confirmButton", IDS_IMAGEBURN_CONFIRM_BUTTON);
78 source->AddLocalizedString("cancelButton", IDS_IMAGEBURN_CANCEL_BUTTON);
79 source->AddLocalizedString("retryButton", IDS_IMAGEBURN_RETRY_BUTTON);
80 source->AddString("moreInfoLink", ASCIIToUTF16(kMoreInfoLink));
81
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000082 source->SetJsonPath("strings.js");
83 source->AddResourcePath("image_burner.js", IDR_IMAGEBURNER_JS);
84 source->SetDefaultResource(IDR_IMAGEBURNER_HTML);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000085 return source;
86}
87
88class WebUIHandler
89 : public content::WebUIMessageHandler,
90 public BurnController::Delegate {
91 public:
92 explicit WebUIHandler(content::WebContents* contents)
93 : burn_controller_(BurnController::CreateBurnController(contents, this)){
94 }
95
96 virtual ~WebUIHandler() {
97 }
98
99 // WebUIMessageHandler implementation.
100 virtual void RegisterMessages() OVERRIDE {
101 web_ui()->RegisterMessageCallback(
102 "getDevices",
103 base::Bind(&WebUIHandler::HandleGetDevices, base::Unretained(this)));
104 web_ui()->RegisterMessageCallback(
105 "burnImage",
106 base::Bind(&WebUIHandler::HandleBurnImage, base::Unretained(this)));
107 web_ui()->RegisterMessageCallback(
108 "cancelBurnImage",
109 base::Bind(&WebUIHandler::HandleCancelBurnImage,
110 base::Unretained(this)));
111 web_ui()->RegisterMessageCallback(
112 "webuiInitialized",
113 base::Bind(&WebUIHandler::HandleWebUIInitialized,
114 base::Unretained(this)));
115 }
116
117 // BurnController::Delegate override.
118 virtual void OnSuccess() OVERRIDE {
119 web_ui()->CallJavascriptFunction("browserBridge.reportSuccess");
120 }
121
122 // BurnController::Delegate override.
123 virtual void OnFail(int error_message_id) OVERRIDE {
124 StringValue error_message(l10n_util::GetStringUTF16(error_message_id));
125 web_ui()->CallJavascriptFunction("browserBridge.reportFail", error_message);
126 }
127
128 // BurnController::Delegate override.
129 virtual void OnDeviceAdded(const disks::DiskMountManager::Disk& disk)
130 OVERRIDE {
131 DictionaryValue disk_value;
132 CreateDiskValue(disk, &disk_value);
133 web_ui()->CallJavascriptFunction("browserBridge.deviceAdded", disk_value);
134 }
135
136 // BurnController::Delegate override.
137 virtual void OnDeviceRemoved(const disks::DiskMountManager::Disk& disk)
138 OVERRIDE {
139 StringValue device_path_value(disk.device_path());
140 web_ui()->CallJavascriptFunction("browserBridge.deviceRemoved",
141 device_path_value);
142 }
143
144 // BurnController::Delegate override.
145 virtual void OnDeviceTooSmall(int64 device_size) OVERRIDE {
146 string16 size;
147 GetDataSizeText(device_size, &size);
148 StringValue device_size_text(size);
149 web_ui()->CallJavascriptFunction("browserBridge.reportDeviceTooSmall",
150 device_size_text);
151 }
152
153 // BurnController::Delegate override.
154 virtual void OnProgress(ProgressType progress_type,
155 int64 amount_finished,
156 int64 amount_total) OVERRIDE {
157 const string16 time_remaining_text =
158 l10n_util::GetStringUTF16(IDS_IMAGEBURN_PROGRESS_TIME_UNKNOWN);
159 SendProgressSignal(progress_type, amount_finished, amount_total,
160 time_remaining_text);
161 }
162
163 // BurnController::Delegate override.
164 virtual void OnProgressWithRemainingTime(
165 ProgressType progress_type,
166 int64 amount_finished,
167 int64 amount_total,
168 const base::TimeDelta& time_remaining) OVERRIDE {
169 const string16 time_remaining_text = l10n_util::GetStringFUTF16(
170 IDS_IMAGEBURN_DOWNLOAD_TIME_REMAINING,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100171 ui::TimeFormat::TimeRemaining(time_remaining));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000172 SendProgressSignal(progress_type, amount_finished, amount_total,
173 time_remaining_text);
174 }
175
176 // BurnController::Delegate override.
177 virtual void OnNetworkDetected() OVERRIDE {
178 web_ui()->CallJavascriptFunction("browserBridge.reportNetworkDetected");
179 }
180
181 // BurnController::Delegate override.
182 virtual void OnNoNetwork() OVERRIDE {
183 web_ui()->CallJavascriptFunction("browserBridge.reportNoNetwork");
184 }
185
186 private:
187 void CreateDiskValue(const disks::DiskMountManager::Disk& disk,
188 DictionaryValue* disk_value) {
189 string16 label = ASCIIToUTF16(disk.drive_label());
190 base::i18n::AdjustStringForLocaleDirection(&label);
191 disk_value->SetString(std::string(kPropertyLabel), label);
192 disk_value->SetString(std::string(kPropertyFilePath), disk.file_path());
193 disk_value->SetString(std::string(kPropertyDevicePath), disk.device_path());
194 disk_value->SetString(std::string(kPropertyDeviceType),
195 disks::DiskMountManager::DeviceTypeToString(disk.device_type()));
196 }
197
198 // Callback for the "getDevices" message.
199 void HandleGetDevices(const ListValue* args) {
200 const std::vector<disks::DiskMountManager::Disk> disks
201 = burn_controller_->GetBurnableDevices();
202 ListValue results_value;
203 for (size_t i = 0; i != disks.size(); ++i) {
204 DictionaryValue* disk_value = new DictionaryValue();
205 CreateDiskValue(disks[i], disk_value);
206 results_value.Append(disk_value);
207 }
208 web_ui()->CallJavascriptFunction("browserBridge.getDevicesCallback",
209 results_value);
210 }
211
212 // Callback for the webuiInitialized message.
213 void HandleWebUIInitialized(const ListValue* args) {
214 burn_controller_->Init();
215 }
216
217 // Callback for the "cancelBurnImage" message.
218 void HandleCancelBurnImage(const ListValue* args) {
219 burn_controller_->CancelBurnImage();
220 }
221
222 // Callback for the "burnImage" message.
223 // It may be called with NULL if there is a handler that has started burning,
224 // and thus set the target paths.
225 void HandleBurnImage(const ListValue* args) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000226 base::FilePath target_device_path;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000227 ExtractTargetedDevicePath(*args, 0, &target_device_path);
228
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000229 base::FilePath target_file_path;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000230 ExtractTargetedDevicePath(*args, 1, &target_file_path);
231
232 burn_controller_->StartBurnImage(target_device_path, target_file_path);
233 }
234
235 // Reports update to UI
236 void SendProgressSignal(ProgressType progress_type,
237 int64 amount_finished,
238 int64 amount_total,
239 const string16& time_remaining_text) {
240 DictionaryValue progress;
241 int progress_message_id = 0;
242 switch (progress_type) {
243 case DOWNLOADING:
244 progress.SetString("progressType", "download");
245 progress_message_id = IDS_IMAGEBURN_DOWNLOAD_PROGRESS_TEXT;
246 break;
247 case UNZIPPING:
248 progress.SetString("progressType", "unzip");
249 break;
250 case BURNING:
251 progress.SetString("progressType", "burn");
252 progress_message_id = IDS_IMAGEBURN_BURN_PROGRESS_TEXT;
253 break;
254 default:
255 return;
256 }
257
258 progress.SetInteger("amountFinished", amount_finished);
259 progress.SetInteger("amountTotal", amount_total);
260 if (amount_total != 0) {
261 string16 progress_text;
262 GetProgressText(progress_message_id, amount_finished, amount_total,
263 &progress_text);
264 progress.SetString("progressText", progress_text);
265 } else {
266 progress.SetString("progressText", "");
267 }
268 progress.SetString("timeLeftText", time_remaining_text);
269
270 web_ui()->CallJavascriptFunction("browserBridge.updateProgress", progress);
271 }
272
273 // size_text should be previously created.
274 void GetDataSizeText(int64 size, string16* size_text) {
275 *size_text = ui::FormatBytes(size);
276 base::i18n::AdjustStringForLocaleDirection(size_text);
277 }
278
279 // progress_text should be previously created.
280 void GetProgressText(int message_id,
281 int64 amount_finished,
282 int64 amount_total,
283 string16* progress_text) {
284 string16 finished;
285 GetDataSizeText(amount_finished, &finished);
286 string16 total;
287 GetDataSizeText(amount_total, &total);
288 *progress_text = l10n_util::GetStringFUTF16(message_id, finished, total);
289 }
290
291 // device_path has to be previously created.
292 void ExtractTargetedDevicePath(const ListValue& list_value,
293 int index,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000294 base::FilePath* device_path) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000295 const Value* list_member;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000296 std::string image_dest;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000297 if (list_value.Get(index, &list_member) &&
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000298 list_member->GetType() == Value::TYPE_STRING &&
299 list_member->GetAsString(&image_dest)) {
300 *device_path = base::FilePath(image_dest);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000301 } else {
302 LOG(ERROR) << "Unable to get path string";
303 device_path->clear();
304 }
305 }
306
307 scoped_ptr<BurnController> burn_controller_;
308
309 DISALLOW_COPY_AND_ASSIGN(WebUIHandler);
310};
311
312} // namespace
313
314} // namespace imageburner
315} // namespace chromeos
316
317////////////////////////////////////////////////////////////////////////////////
318//
319// ImageBurnUI
320//
321////////////////////////////////////////////////////////////////////////////////
322
323ImageBurnUI::ImageBurnUI(content::WebUI* web_ui) : WebUIController(web_ui) {
324 chromeos::imageburner::WebUIHandler* handler =
325 new chromeos::imageburner::WebUIHandler(web_ui->GetWebContents());
326 web_ui->AddMessageHandler(handler);
327
328 Profile* profile = Profile::FromWebUI(web_ui);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000329 content::WebUIDataSource::Add(
330 profile, chromeos::imageburner::CreateImageburnerUIHTMLSource());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000331}