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