// Copyright (c) 2011 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/register_page_ui.h"
#include <string>
#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/system_access.h"
#include "chrome/browser/chromeos/version_loader.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
#include "grit/browser_resources.h"
#include "ui/base/resource/resource_bundle.h"
namespace {
// Host page JS API callback names.
const char kJsCallbackGetRegistrationUrl[] = "getRegistrationUrl";
const char kJsCallbackUserInfo[] = "getUserInfo";
// Host page JS API function names.
const char kJsApiSetRegistrationUrl[] = "setRegistrationUrl";
const char kJsApiSetUserInfo[] = "setUserInfo";
const char kJsApiSkipRegistration[] = "skipRegistration";
// Constant value for os_name sent in setUserInfo.
const char kOSName[] = "ChromeOS";
// MachineInfo keys names.
const char kMachineInfoSystemHwqual[] = "hardware_class";
const char kMachineInfoSerialNumber[] = "serial_number";
// Types of network connection.
const char kConnectionEthernet[] = "ethernet";
const char kConnectionWifi[] = "wifi";
const char kConnection3g[] = "3g";
const char kUndefinedValue[] = "undefined";
// Utility function that returns string corresponding to currently active
// connection type |kConnectionEthernet|kConnectionWifi|kConnection3g|.
// If multiple interfaces are connected, result is based on the
// priority Ethernet-Wifi-Cellular.
// If there's no interface that's connected, interface that's in connecting
// state is considered as the active one.
// Otherwise |kUndefinedValue| is returned.
#if defined(OS_CHROMEOS)
static std::string GetConnectionType() {
if (!chromeos::CrosLibrary::Get()->EnsureLoaded()) {
LOG(ERROR) << "CrosLibrary is not loaded.";
return kUndefinedValue;
}
chromeos::NetworkLibrary* network_lib =
chromeos::CrosLibrary::Get()->GetNetworkLibrary();
if (network_lib->ethernet_connected())
return kConnectionEthernet;
else if (network_lib->wifi_connected())
return kConnectionWifi;
else if (network_lib->cellular_connected())
return kConnection3g;
// Connection might have been lost and is in reconnecting state at this point.
else if (network_lib->ethernet_connecting())
return kConnectionEthernet;
else if (network_lib->wifi_connecting())
return kConnectionWifi;
else if (network_lib->cellular_connecting())
return kConnection3g;
else
return kUndefinedValue;
}
#endif
} // namespace
class RegisterPageUIHTMLSource : public ChromeURLDataManager::DataSource {
public:
RegisterPageUIHTMLSource();
// Called when the network layer has requested a resource underneath
// the path we registered.
virtual void StartDataRequest(const std::string& path,
bool is_incognito,
int request_id);
virtual std::string GetMimeType(const std::string&) const {
return "text/html";
}
private:
~RegisterPageUIHTMLSource() {}
DISALLOW_COPY_AND_ASSIGN(RegisterPageUIHTMLSource);
};
// The handler for Javascript messages related to the "register" view.
class RegisterPageHandler : public WebUIMessageHandler,
public base::SupportsWeakPtr<RegisterPageHandler> {
public:
RegisterPageHandler();
virtual ~RegisterPageHandler();
// Init work after Attach.
void Init();
// WebUIMessageHandler implementation.
virtual WebUIMessageHandler* Attach(WebUI* web_ui);
virtual void RegisterMessages();
private:
// Handlers for JS WebUI messages.
void HandleGetRegistrationUrl(const ListValue* args);
void HandleGetUserInfo(const ListValue* args);
#if defined(OS_CHROMEOS)
// Callback from chromeos::VersionLoader giving the version.
void OnVersion(chromeos::VersionLoader::Handle handle, std::string version);
#endif
// Skips registration logging |error_msg| with log type ERROR.
void SkipRegistration(const std::string& error_msg);
// Sends message to host registration page with system/user info data.
void SendUserInfo();
#if defined(OS_CHROMEOS)
// Handles asynchronously loading the version.
chromeos::VersionLoader version_loader_;
#endif
// Used to request the version.
CancelableRequestConsumer version_consumer_;
std::string version_;
DISALLOW_COPY_AND_ASSIGN(RegisterPageHandler);
};
////////////////////////////////////////////////////////////////////////////////
//
// RegisterPageUIHTMLSource
//
////////////////////////////////////////////////////////////////////////////////
RegisterPageUIHTMLSource::RegisterPageUIHTMLSource()
: DataSource(chrome::kChromeUIRegisterPageHost, MessageLoop::current()) {
}
void RegisterPageUIHTMLSource::StartDataRequest(const std::string& path,
bool is_incognito,
int request_id) {
// Make sure that chrome://register is available only during
// OOBE wizard lifetime and when device has not been registered yet.
#if defined(OS_CHROMEOS)
if (!WizardController::default_controller() ||
WizardController::IsDeviceRegistered()) {
scoped_refptr<RefCountedBytes> empty_bytes(new RefCountedBytes);
SendResponse(request_id, empty_bytes);
return;
}
static const base::StringPiece register_html(
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_HOST_REGISTRATION_PAGE_HTML));
scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
html_bytes->data.resize(register_html.size());
std::copy(register_html.begin(),
register_html.end(),
html_bytes->data.begin());
SendResponse(request_id, html_bytes);
#else
scoped_refptr<RefCountedBytes> empty_bytes(new RefCountedBytes);
SendResponse(request_id, empty_bytes);
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
// RegisterPageHandler
//
////////////////////////////////////////////////////////////////////////////////
RegisterPageHandler::RegisterPageHandler() {
}
RegisterPageHandler::~RegisterPageHandler() {
}
WebUIMessageHandler* RegisterPageHandler::Attach(WebUI* web_ui) {
return WebUIMessageHandler::Attach(web_ui);
}
void RegisterPageHandler::Init() {
}
void RegisterPageHandler::RegisterMessages() {
#if defined(OS_CHROMEOS)
web_ui_->RegisterMessageCallback(kJsCallbackGetRegistrationUrl,
NewCallback(this, &RegisterPageHandler::HandleGetRegistrationUrl));
web_ui_->RegisterMessageCallback(kJsCallbackUserInfo,
NewCallback(this, &RegisterPageHandler::HandleGetUserInfo));
#endif
}
void RegisterPageHandler::HandleGetRegistrationUrl(const ListValue* args) {
#if defined(OS_CHROMEOS)
chromeos::StartupCustomizationDocument* customization =
chromeos::StartupCustomizationDocument::GetInstance();
if (WizardController::default_controller() &&
customization->IsReady()) {
const std::string& url = customization->registration_url();
VLOG(1) << "Loading registration form with URL: " << url;
GURL register_url(url);
if (!register_url.is_valid()) {
SkipRegistration("Registration URL defined in manifest is invalid.");
return;
}
StringValue url_value(url);
web_ui_->CallJavascriptFunction(kJsApiSetRegistrationUrl, url_value);
} else {
SkipRegistration("Startup manifest not defined.");
}
#endif
}
void RegisterPageHandler::HandleGetUserInfo(const ListValue* args) {
#if defined(OS_CHROMEOS)
if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
version_loader_.GetVersion(
&version_consumer_,
NewCallback(this,
&RegisterPageHandler::OnVersion),
chromeos::VersionLoader::VERSION_FULL);
} else {
SkipRegistration("CrosLibrary is not loaded.");
}
#endif
}
#if defined(OS_CHROMEOS)
void RegisterPageHandler::OnVersion(chromeos::VersionLoader::Handle handle,
std::string version) {
version_ = version;
SendUserInfo();
}
#endif
void RegisterPageHandler::SkipRegistration(const std::string& error_msg) {
#if defined(OS_CHROMEOS)
LOG(ERROR) << error_msg;
if (WizardController::default_controller())
WizardController::default_controller()->SkipRegistration();
else
web_ui_->CallJavascriptFunction(kJsApiSkipRegistration);
#endif
}
void RegisterPageHandler::SendUserInfo() {
#if defined(OS_CHROMEOS)
DictionaryValue value;
chromeos::SystemAccess * sys_lib =
chromeos::SystemAccess::GetInstance();
// Required info.
std::string system_hwqual;
std::string serial_number;
if (!sys_lib->GetMachineStatistic(kMachineInfoSystemHwqual, &system_hwqual) ||
!sys_lib->GetMachineStatistic(kMachineInfoSerialNumber, &serial_number)) {
SkipRegistration("Failed to get required machine info.");
return;
}
value.SetString("system_hwqual", system_hwqual);
value.SetString("system_serial", serial_number);
value.SetString("os_language", g_browser_process->GetApplicationLocale());
value.SetString("os_name", kOSName);
value.SetString("os_version", version_);
value.SetString("os_connection", GetConnectionType());
value.SetString("user_email", "");
// Optional info.
value.SetString("user_first_name", "");
value.SetString("user_last_name", "");
web_ui_->CallJavascriptFunction(kJsApiSetUserInfo, value);
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
// RegisterPageUI
//
////////////////////////////////////////////////////////////////////////////////
RegisterPageUI::RegisterPageUI(TabContents* contents) : WebUI(contents){
RegisterPageHandler* handler = new RegisterPageHandler();
AddMessageHandler((handler)->Attach(this));
handler->Init();
RegisterPageUIHTMLSource* html_source = new RegisterPageUIHTMLSource();
// Set up the chrome://register/ source.
contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
}