blob: 08b3146a7e4cade2f1f971c18945d3a056bf971c [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/i18n/rtl.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/imageburner/burn_controller.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/time_format.h"
#include "ui/base/text/bytes_formatting.h"
#include "url/gurl.h"
namespace chromeos {
namespace imageburner {
namespace {
const char kPropertyDevicePath[] = "devicePath";
const char kPropertyFilePath[] = "filePath";
const char kPropertyLabel[] = "label";
const char kPropertyDeviceType[] = "type";
// Link displayed on imageburner ui.
const char kMoreInfoLink[] =
"http://www.chromium.org/chromium-os/chromiumos-design-docs/recovery-mode";
content::WebUIDataSource* CreateImageburnerUIHTMLSource() {
content::WebUIDataSource* source =
content::WebUIDataSource::Create(chrome::kChromeUIImageBurnerHost);
source->AddLocalizedString("headerTitle", IDS_IMAGEBURN_HEADER_TITLE);
source->AddLocalizedString("headerDescription",
IDS_IMAGEBURN_HEADER_DESCRIPTION);
source->AddLocalizedString("headerLink", IDS_IMAGEBURN_HEADER_LINK);
source->AddLocalizedString("statusDevicesNone",
IDS_IMAGEBURN_NO_DEVICES_STATUS);
source->AddLocalizedString("warningDevicesNone",
IDS_IMAGEBURN_NO_DEVICES_WARNING);
source->AddLocalizedString("statusDevicesMultiple",
IDS_IMAGEBURN_MUL_DEVICES_STATUS);
source->AddLocalizedString("statusDeviceUSB",
IDS_IMAGEBURN_USB_DEVICE_STATUS);
source->AddLocalizedString("statusDeviceSD",
IDS_IMAGEBURN_SD_DEVICE_STATUS);
source->AddLocalizedString("warningDevices",
IDS_IMAGEBURN_DEVICES_WARNING);
source->AddLocalizedString("statusNoConnection",
IDS_IMAGEBURN_NO_CONNECTION_STATUS);
source->AddLocalizedString("warningNoConnection",
IDS_IMAGEBURN_NO_CONNECTION_WARNING);
source->AddLocalizedString("statusNoSpace",
IDS_IMAGEBURN_INSUFFICIENT_SPACE_STATUS);
source->AddLocalizedString("warningNoSpace",
IDS_IMAGEBURN_INSUFFICIENT_SPACE_WARNING);
source->AddLocalizedString("statusDownloading",
IDS_IMAGEBURN_DOWNLOADING_STATUS);
source->AddLocalizedString("statusUnzip", IDS_IMAGEBURN_UNZIP_STATUS);
source->AddLocalizedString("statusBurn", IDS_IMAGEBURN_BURN_STATUS);
source->AddLocalizedString("statusError", IDS_IMAGEBURN_ERROR_STATUS);
source->AddLocalizedString("statusSuccess", IDS_IMAGEBURN_SUCCESS_STATUS);
source->AddLocalizedString("warningSuccess", IDS_IMAGEBURN_SUCCESS_DESC);
source->AddLocalizedString("title", IDS_IMAGEBURN_PAGE_TITLE);
source->AddLocalizedString("confirmButton", IDS_IMAGEBURN_CONFIRM_BUTTON);
source->AddLocalizedString("cancelButton", IDS_IMAGEBURN_CANCEL_BUTTON);
source->AddLocalizedString("retryButton", IDS_IMAGEBURN_RETRY_BUTTON);
source->AddString("moreInfoLink", ASCIIToUTF16(kMoreInfoLink));
source->SetJsonPath("strings.js");
source->AddResourcePath("image_burner.js", IDR_IMAGEBURNER_JS);
source->SetDefaultResource(IDR_IMAGEBURNER_HTML);
return source;
}
class WebUIHandler
: public content::WebUIMessageHandler,
public BurnController::Delegate {
public:
explicit WebUIHandler(content::WebContents* contents)
: burn_controller_(BurnController::CreateBurnController(contents, this)){
}
virtual ~WebUIHandler() {
}
// WebUIMessageHandler implementation.
virtual void RegisterMessages() OVERRIDE {
web_ui()->RegisterMessageCallback(
"getDevices",
base::Bind(&WebUIHandler::HandleGetDevices, base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"burnImage",
base::Bind(&WebUIHandler::HandleBurnImage, base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"cancelBurnImage",
base::Bind(&WebUIHandler::HandleCancelBurnImage,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"webuiInitialized",
base::Bind(&WebUIHandler::HandleWebUIInitialized,
base::Unretained(this)));
}
// BurnController::Delegate override.
virtual void OnSuccess() OVERRIDE {
web_ui()->CallJavascriptFunction("browserBridge.reportSuccess");
}
// BurnController::Delegate override.
virtual void OnFail(int error_message_id) OVERRIDE {
StringValue error_message(l10n_util::GetStringUTF16(error_message_id));
web_ui()->CallJavascriptFunction("browserBridge.reportFail", error_message);
}
// BurnController::Delegate override.
virtual void OnDeviceAdded(const disks::DiskMountManager::Disk& disk)
OVERRIDE {
DictionaryValue disk_value;
CreateDiskValue(disk, &disk_value);
web_ui()->CallJavascriptFunction("browserBridge.deviceAdded", disk_value);
}
// BurnController::Delegate override.
virtual void OnDeviceRemoved(const disks::DiskMountManager::Disk& disk)
OVERRIDE {
StringValue device_path_value(disk.device_path());
web_ui()->CallJavascriptFunction("browserBridge.deviceRemoved",
device_path_value);
}
// BurnController::Delegate override.
virtual void OnDeviceTooSmall(int64 device_size) OVERRIDE {
string16 size;
GetDataSizeText(device_size, &size);
StringValue device_size_text(size);
web_ui()->CallJavascriptFunction("browserBridge.reportDeviceTooSmall",
device_size_text);
}
// BurnController::Delegate override.
virtual void OnProgress(ProgressType progress_type,
int64 amount_finished,
int64 amount_total) OVERRIDE {
const string16 time_remaining_text =
l10n_util::GetStringUTF16(IDS_IMAGEBURN_PROGRESS_TIME_UNKNOWN);
SendProgressSignal(progress_type, amount_finished, amount_total,
time_remaining_text);
}
// BurnController::Delegate override.
virtual void OnProgressWithRemainingTime(
ProgressType progress_type,
int64 amount_finished,
int64 amount_total,
const base::TimeDelta& time_remaining) OVERRIDE {
const string16 time_remaining_text = l10n_util::GetStringFUTF16(
IDS_IMAGEBURN_DOWNLOAD_TIME_REMAINING,
ui::TimeFormat::TimeRemaining(time_remaining));
SendProgressSignal(progress_type, amount_finished, amount_total,
time_remaining_text);
}
// BurnController::Delegate override.
virtual void OnNetworkDetected() OVERRIDE {
web_ui()->CallJavascriptFunction("browserBridge.reportNetworkDetected");
}
// BurnController::Delegate override.
virtual void OnNoNetwork() OVERRIDE {
web_ui()->CallJavascriptFunction("browserBridge.reportNoNetwork");
}
private:
void CreateDiskValue(const disks::DiskMountManager::Disk& disk,
DictionaryValue* disk_value) {
string16 label = ASCIIToUTF16(disk.drive_label());
base::i18n::AdjustStringForLocaleDirection(&label);
disk_value->SetString(std::string(kPropertyLabel), label);
disk_value->SetString(std::string(kPropertyFilePath), disk.file_path());
disk_value->SetString(std::string(kPropertyDevicePath), disk.device_path());
disk_value->SetString(std::string(kPropertyDeviceType),
disks::DiskMountManager::DeviceTypeToString(disk.device_type()));
}
// Callback for the "getDevices" message.
void HandleGetDevices(const ListValue* args) {
const std::vector<disks::DiskMountManager::Disk> disks
= burn_controller_->GetBurnableDevices();
ListValue results_value;
for (size_t i = 0; i != disks.size(); ++i) {
DictionaryValue* disk_value = new DictionaryValue();
CreateDiskValue(disks[i], disk_value);
results_value.Append(disk_value);
}
web_ui()->CallJavascriptFunction("browserBridge.getDevicesCallback",
results_value);
}
// Callback for the webuiInitialized message.
void HandleWebUIInitialized(const ListValue* args) {
burn_controller_->Init();
}
// Callback for the "cancelBurnImage" message.
void HandleCancelBurnImage(const ListValue* args) {
burn_controller_->CancelBurnImage();
}
// Callback for the "burnImage" message.
// It may be called with NULL if there is a handler that has started burning,
// and thus set the target paths.
void HandleBurnImage(const ListValue* args) {
base::FilePath target_device_path;
ExtractTargetedDevicePath(*args, 0, &target_device_path);
base::FilePath target_file_path;
ExtractTargetedDevicePath(*args, 1, &target_file_path);
burn_controller_->StartBurnImage(target_device_path, target_file_path);
}
// Reports update to UI
void SendProgressSignal(ProgressType progress_type,
int64 amount_finished,
int64 amount_total,
const string16& time_remaining_text) {
DictionaryValue progress;
int progress_message_id = 0;
switch (progress_type) {
case DOWNLOADING:
progress.SetString("progressType", "download");
progress_message_id = IDS_IMAGEBURN_DOWNLOAD_PROGRESS_TEXT;
break;
case UNZIPPING:
progress.SetString("progressType", "unzip");
break;
case BURNING:
progress.SetString("progressType", "burn");
progress_message_id = IDS_IMAGEBURN_BURN_PROGRESS_TEXT;
break;
default:
return;
}
progress.SetInteger("amountFinished", amount_finished);
progress.SetInteger("amountTotal", amount_total);
if (amount_total != 0) {
string16 progress_text;
GetProgressText(progress_message_id, amount_finished, amount_total,
&progress_text);
progress.SetString("progressText", progress_text);
} else {
progress.SetString("progressText", "");
}
progress.SetString("timeLeftText", time_remaining_text);
web_ui()->CallJavascriptFunction("browserBridge.updateProgress", progress);
}
// size_text should be previously created.
void GetDataSizeText(int64 size, string16* size_text) {
*size_text = ui::FormatBytes(size);
base::i18n::AdjustStringForLocaleDirection(size_text);
}
// progress_text should be previously created.
void GetProgressText(int message_id,
int64 amount_finished,
int64 amount_total,
string16* progress_text) {
string16 finished;
GetDataSizeText(amount_finished, &finished);
string16 total;
GetDataSizeText(amount_total, &total);
*progress_text = l10n_util::GetStringFUTF16(message_id, finished, total);
}
// device_path has to be previously created.
void ExtractTargetedDevicePath(const ListValue& list_value,
int index,
base::FilePath* device_path) {
const Value* list_member;
std::string image_dest;
if (list_value.Get(index, &list_member) &&
list_member->GetType() == Value::TYPE_STRING &&
list_member->GetAsString(&image_dest)) {
*device_path = base::FilePath(image_dest);
} else {
LOG(ERROR) << "Unable to get path string";
device_path->clear();
}
}
scoped_ptr<BurnController> burn_controller_;
DISALLOW_COPY_AND_ASSIGN(WebUIHandler);
};
} // namespace
} // namespace imageburner
} // namespace chromeos
////////////////////////////////////////////////////////////////////////////////
//
// ImageBurnUI
//
////////////////////////////////////////////////////////////////////////////////
ImageBurnUI::ImageBurnUI(content::WebUI* web_ui) : WebUIController(web_ui) {
chromeos::imageburner::WebUIHandler* handler =
new chromeos::imageburner::WebUIHandler(web_ui->GetWebContents());
web_ui->AddMessageHandler(handler);
Profile* profile = Profile::FromWebUI(web_ui);
content::WebUIDataSource::Add(
profile, chromeos::imageburner::CreateImageburnerUIHTMLSource());
}