blob: 374f2eedc96515ee6a892a2046adcc9880717854 [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/help/help_handler.h"
#include <string>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_ui.h"
#include "content/public/common/content_client.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/google_chrome_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "v8/include/v8.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/user_agent/user_agent_util.h"
#if defined(OS_CHROMEOS)
#include "base/file_util_proxy.h"
#include "base/i18n/time_formatting.h"
#include "base/sys_info.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#endif
using base::ListValue;
using content::BrowserThread;
namespace {
// Returns the browser version as a string.
string16 BuildBrowserVersionString() {
chrome::VersionInfo version_info;
DCHECK(version_info.is_valid());
std::string browser_version = version_info.Version();
std::string version_modifier =
chrome::VersionInfo::GetVersionStringModifier();
if (!version_modifier.empty())
browser_version += " " + version_modifier;
#if !defined(GOOGLE_CHROME_BUILD)
browser_version += " (";
browser_version += version_info.LastChange();
browser_version += ")";
#endif
return UTF8ToUTF16(browser_version);
}
#if defined(OS_CHROMEOS)
bool CanChangeReleaseChannel() {
// On non managed machines we have local owner who is the only one to change
// anything.
if (chromeos::UserManager::Get()->IsCurrentUserOwner())
return true;
// On a managed machine we delegate this setting to the users of the same
// domain only if the policy value is "domain".
if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
bool value = false;
if (!chromeos::CrosSettings::Get()->GetBoolean(
chromeos::kReleaseChannelDelegated, &value) || !value)
return false;
// Get the currently logged in user and strip the domain part only.
std::string domain = "";
std::string user = chromeos::UserManager::Get()->GetLoggedInUser().email();
size_t at_pos = user.find('@');
if (at_pos != std::string::npos && at_pos + 1 < user.length())
domain = user.substr(user.find('@') + 1);
return domain == g_browser_process->browser_policy_connector()->
GetEnterpriseDomain();
}
return false;
}
// Pointer to a |StringValue| holding the date of the build date to Chromium
// OS. Because this value is obtained by reading a file, it is cached here to
// prevent the need to read from the file system multiple times unnecessarily.
Value* g_build_date_string = NULL;
#endif // defined(OS_CHROMEOS)
} // namespace
HelpHandler::HelpHandler()
: version_updater_(VersionUpdater::Create()),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
}
HelpHandler::~HelpHandler() {
}
void HelpHandler::GetLocalizedValues(DictionaryValue* localized_strings) {
DCHECK(localized_strings);
DCHECK(localized_strings->empty());
struct L10nResources {
const char* name;
int ids;
};
static L10nResources resources[] = {
{ "helpTitle", IDS_HELP_TITLE },
{ "aboutTitle", IDS_ABOUT_TAB_TITLE },
#if defined(OS_CHROMEOS)
{ "aboutProductTitle", IDS_PRODUCT_OS_NAME },
#else
{ "aboutProductTitle", IDS_PRODUCT_NAME },
#endif
{ "aboutProductDescription", IDS_ABOUT_PRODUCT_DESCRIPTION },
{ "relaunch", IDS_RELAUNCH_BUTTON },
{ "productName", IDS_PRODUCT_NAME },
{ "productCopyright", IDS_ABOUT_VERSION_COPYRIGHT },
{ "updateCheckStarted", IDS_UPGRADE_CHECK_STARTED },
{ "upToDate", IDS_UPGRADE_UP_TO_DATE },
{ "updating", IDS_UPGRADE_UPDATING },
{ "updateAlmostDone", IDS_UPGRADE_SUCCESSFUL_RELAUNCH },
{ "getHelpWithChrome", IDS_GET_HELP_USING_CHROME },
{ "reportAnIssue", IDS_REPORT_AN_ISSUE },
#if defined(OS_CHROMEOS)
{ "platform", IDS_PLATFORM_LABEL },
{ "firmware", IDS_ABOUT_PAGE_FIRMWARE },
{ "showMoreInfo", IDS_SHOW_MORE_INFO },
{ "hideMoreInfo", IDS_HIDE_MORE_INFO },
{ "channel", IDS_ABOUT_PAGE_CHANNEL },
{ "stable", IDS_ABOUT_PAGE_CHANNEL_STABLE },
{ "beta", IDS_ABOUT_PAGE_CHANNEL_BETA },
{ "dev", IDS_ABOUT_PAGE_CHANNEL_DEVELOPMENT },
{ "channel-changed", IDS_ABOUT_PAGE_CHANNEL_CHANGED },
{ "webkit", IDS_WEBKIT },
{ "userAgent", IDS_ABOUT_VERSION_USER_AGENT },
{ "commandLine", IDS_ABOUT_VERSION_COMMAND_LINE },
{ "buildDate", IDS_ABOUT_VERSION_BUILD_DATE },
#endif
#if defined(OS_MACOSX)
{ "promote", IDS_ABOUT_CHROME_PROMOTE_UPDATER },
{ "learnMore", IDS_LEARN_MORE },
#endif
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(resources); ++i) {
localized_strings->SetString(resources[i].name,
l10n_util::GetStringUTF16(resources[i].ids));
}
localized_strings->SetString(
"browserVersion",
l10n_util::GetStringFUTF16(IDS_ABOUT_PRODUCT_VERSION,
BuildBrowserVersionString()));
string16 license = l10n_util::GetStringFUTF16(
IDS_ABOUT_VERSION_LICENSE,
ASCIIToUTF16(chrome::kChromiumProjectURL),
ASCIIToUTF16(chrome::kChromeUICreditsURL));
localized_strings->SetString("productLicense", license);
#if defined(OS_CHROMEOS)
string16 os_license = l10n_util::GetStringFUTF16(
IDS_ABOUT_CROS_VERSION_LICENSE,
ASCIIToUTF16(chrome::kChromeUIOSCreditsURL));
localized_strings->SetString("productOsLicense", os_license);
#endif
string16 tos = l10n_util::GetStringFUTF16(
IDS_ABOUT_TERMS_OF_SERVICE, UTF8ToUTF16(chrome::kChromeUITermsURL));
localized_strings->SetString("productTOS", tos);
localized_strings->SetString("webkitVersion",
webkit_glue::GetWebKitVersion());
localized_strings->SetString("jsEngine", "V8");
localized_strings->SetString("jsEngineVersion", v8::V8::GetVersion());
localized_strings->SetString("userAgentInfo",
content::GetUserAgent(GURL()));
CommandLine::StringType command_line =
CommandLine::ForCurrentProcess()->GetCommandLineString();
localized_strings->SetString("commandLineInfo", command_line);
}
void HelpHandler::RegisterMessages() {
registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
content::NotificationService::AllSources());
web_ui()->RegisterMessageCallback("onPageLoaded",
base::Bind(&HelpHandler::OnPageLoaded, base::Unretained(this)));
web_ui()->RegisterMessageCallback("relaunchNow",
base::Bind(&HelpHandler::RelaunchNow, base::Unretained(this)));
web_ui()->RegisterMessageCallback("openFeedbackDialog",
base::Bind(&HelpHandler::OpenFeedbackDialog, base::Unretained(this)));
web_ui()->RegisterMessageCallback("openHelpPage",
base::Bind(&HelpHandler::OpenHelpPage, base::Unretained(this)));
#if defined(OS_CHROMEOS)
web_ui()->RegisterMessageCallback("setReleaseTrack",
base::Bind(&HelpHandler::SetReleaseTrack, base::Unretained(this)));
#endif
#if defined(OS_MACOSX)
web_ui()->RegisterMessageCallback("promoteUpdater",
base::Bind(&HelpHandler::PromoteUpdater, base::Unretained(this)));
#endif
}
void HelpHandler::Observe(int type, const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: {
// A version update is installed and ready to go. Refresh the UI so the
// correct state will be shown.
version_updater_->CheckForUpdate(
base::Bind(&HelpHandler::SetUpdateStatus, base::Unretained(this))
#if defined(OS_MACOSX)
, base::Bind(&HelpHandler::SetPromotionState, base::Unretained(this))
#endif
);
break;
}
default:
NOTREACHED();
}
}
void HelpHandler::OnPageLoaded(const ListValue* args) {
#if defined(OS_CHROMEOS)
// Version information is loaded from a callback
loader_.GetVersion(&consumer_, base::Bind(&HelpHandler::OnOSVersion,
base::Unretained(this)),
chromeos::VersionLoader::VERSION_FULL);
loader_.GetFirmware(&consumer_, base::Bind(&HelpHandler::OnOSFirmware,
base::Unretained(this)));
scoped_ptr<base::Value> can_change_channel_value(
base::Value::CreateBooleanValue(CanChangeReleaseChannel()));
web_ui()->CallJavascriptFunction(
"help.HelpPage.updateEnableReleaseChannel", *can_change_channel_value);
if (g_build_date_string == NULL) {
// If |g_build_date_string| is |NULL|, the date has not yet been assigned.
// Get the date of the last lsb-release file modification.
base::FileUtilProxy::GetFileInfo(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
base::SysInfo::GetLsbReleaseFilePath(),
base::Bind(&HelpHandler::ProcessLsbFileInfo,
weak_factory_.GetWeakPtr()));
} else {
web_ui()->CallJavascriptFunction("help.HelpPage.setBuildDate",
*g_build_date_string);
}
#endif // defined(OS_CHROMEOS)
version_updater_->CheckForUpdate(
base::Bind(&HelpHandler::SetUpdateStatus, base::Unretained(this))
#if defined(OS_MACOSX)
, base::Bind(&HelpHandler::SetPromotionState, base::Unretained(this))
#endif
);
#if defined(OS_CHROMEOS)
version_updater_->GetReleaseChannel(
base::Bind(&HelpHandler::OnReleaseChannel, base::Unretained(this)));
#endif
}
#if defined(OS_MACOSX)
void HelpHandler::PromoteUpdater(const ListValue* args) {
version_updater_->PromoteUpdater();
}
#endif
void HelpHandler::RelaunchNow(const ListValue* args) {
DCHECK(args->empty());
version_updater_->RelaunchBrowser();
}
void HelpHandler::OpenFeedbackDialog(const ListValue* args) {
DCHECK(args->empty());
Browser* browser = browser::FindBrowserWithWebContents(
web_ui()->GetWebContents());
chrome::OpenFeedbackDialog(browser);
}
void HelpHandler::OpenHelpPage(const base::ListValue* args) {
DCHECK(args->empty());
Browser* browser = browser::FindBrowserWithWebContents(
web_ui()->GetWebContents());
chrome::ShowHelp(browser, chrome::HELP_SOURCE_WEBUI);
}
#if defined(OS_CHROMEOS)
void HelpHandler::SetReleaseTrack(const ListValue* args) {
if (!CanChangeReleaseChannel()) {
LOG(WARNING) << "Non-owner tried to change release track.";
return;
}
const std::string channel = UTF16ToUTF8(ExtractStringValue(args));
version_updater_->SetReleaseChannel(channel);
// On enterprise machines we can only use SetReleaseChannel to store the
// user choice in the lsb-release file but we can not modify the policy blob.
// Therefore we only call SetString if the device is locally owned and the
// currently logged in user is the owner.
if (chromeos::UserManager::Get()->IsCurrentUserOwner()) {
chromeos::CrosSettings::Get()->SetString(chromeos::kReleaseChannel,
channel);
// Check for update after switching release channel.
version_updater_->CheckForUpdate(base::Bind(&HelpHandler::SetUpdateStatus,
base::Unretained(this)));
}
}
#endif // defined(OS_CHROMEOS)
void HelpHandler::SetUpdateStatus(VersionUpdater::Status status,
int progress, const string16& message) {
// Only UPDATING state should have progress set.
DCHECK(status == VersionUpdater::UPDATING || progress == 0);
std::string status_str;
switch (status) {
case VersionUpdater::CHECKING:
status_str = "checking";
break;
case VersionUpdater::UPDATING:
status_str = "updating";
break;
case VersionUpdater::NEARLY_UPDATED:
status_str = "nearly_updated";
break;
case VersionUpdater::UPDATED:
status_str = "updated";
break;
case VersionUpdater::FAILED:
status_str = "failed";
break;
case VersionUpdater::DISABLED:
status_str = "disabled";
break;
}
scoped_ptr<Value> status_value(Value::CreateStringValue(status_str));
scoped_ptr<Value> message_value(Value::CreateStringValue(message));
web_ui()->CallJavascriptFunction("help.HelpPage.setUpdateStatus",
*status_value, *message_value);
if (status == VersionUpdater::UPDATING) {
scoped_ptr<Value> progress_value(Value::CreateIntegerValue(progress));
web_ui()->CallJavascriptFunction("help.HelpPage.setProgress",
*progress_value);
}
}
#if defined(OS_MACOSX)
void HelpHandler::SetPromotionState(VersionUpdater::PromotionState state) {
std::string state_str;
switch (state) {
case VersionUpdater::PROMOTE_HIDDEN:
state_str = "hidden";
break;
case VersionUpdater::PROMOTE_ENABLED:
state_str = "enabled";
break;
case VersionUpdater::PROMOTE_DISABLED:
state_str = "disabled";
break;
}
scoped_ptr<Value> state_value(Value::CreateStringValue(state_str));
web_ui()->CallJavascriptFunction("help.HelpPage.setPromotionState",
*state_value);
}
#endif // defined(OS_MACOSX)
#if defined(OS_CHROMEOS)
void HelpHandler::OnOSVersion(chromeos::VersionLoader::Handle handle,
const std::string& version) {
scoped_ptr<Value> version_string(Value::CreateStringValue(version));
web_ui()->CallJavascriptFunction("help.HelpPage.setOSVersion",
*version_string);
}
void HelpHandler::OnOSFirmware(chromeos::VersionLoader::Handle handle,
const std::string& firmware) {
scoped_ptr<Value> firmware_string(Value::CreateStringValue(firmware));
web_ui()->CallJavascriptFunction("help.HelpPage.setOSFirmware",
*firmware_string);
}
void HelpHandler::OnReleaseChannel(const std::string& channel) {
scoped_ptr<Value> channel_string(Value::CreateStringValue(channel));
web_ui()->CallJavascriptFunction(
"help.HelpPage.updateSelectedChannel", *channel_string);
}
void HelpHandler::ProcessLsbFileInfo(
base::PlatformFileError error, const base::PlatformFileInfo& file_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// If |g_build_date_string| is not |NULL|, then the file's information has
// already been retrieved by another tab.
if (g_build_date_string == NULL) {
base::Time time;
if (error == base::PLATFORM_FILE_OK) {
// Retrieves the time at which the Chrome OS build was created.
// Each time a new build is created, /etc/lsb-release is modified with the
// new version numbers of the release.
time = file_info.last_modified;
} else {
// If the time of the build cannot be retrieved, return and do not
// display the "Build Date" section.
return;
}
// Note that this string will be internationalized.
string16 build_date = base::TimeFormatFriendlyDate(time);
g_build_date_string = Value::CreateStringValue(build_date);
}
web_ui()->CallJavascriptFunction("help.HelpPage.setBuildDate",
*g_build_date_string);
}
#endif // defined(OS_CHROMEOS)