help_handler.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/help/help_handler.h" 6 7#include <string> 8 9#include "base/basictypes.h" 10#include "base/bind.h" 11#include "base/bind_helpers.h" 12#include "base/command_line.h" 13#include "base/strings/string16.h" 14#include "base/strings/utf_string_conversions.h" 15#include "base/values.h" 16#include "chrome/browser/browser_process.h" 17#include "chrome/browser/google/google_util.h" 18#include "chrome/browser/policy/browser_policy_connector.h" 19#include "chrome/browser/ui/browser.h" 20#include "chrome/browser/ui/browser_commands.h" 21#include "chrome/browser/ui/browser_finder.h" 22#include "chrome/browser/ui/chrome_pages.h" 23#include "chrome/browser/ui/send_feedback_experiment.h" 24#include "chrome/common/chrome_notification_types.h" 25#include "chrome/common/chrome_version_info.h" 26#include "chrome/common/url_constants.h" 27#include "content/public/browser/browser_thread.h" 28#include "content/public/browser/notification_service.h" 29#include "content/public/browser/web_ui.h" 30#include "content/public/browser/web_ui_data_source.h" 31#include "content/public/common/content_client.h" 32#include "grit/chromium_strings.h" 33#include "grit/generated_resources.h" 34#include "grit/google_chrome_strings.h" 35#include "ui/base/l10n/l10n_util.h" 36#include "ui/base/resource/resource_bundle.h" 37#include "v8/include/v8.h" 38#include "webkit/common/user_agent/user_agent_util.h" 39#include "webkit/glue/webkit_glue.h" 40 41#if defined(OS_CHROMEOS) 42#include "base/files/file_util_proxy.h" 43#include "base/i18n/time_formatting.h" 44#include "base/prefs/pref_service.h" 45#include "base/sys_info.h" 46#include "chrome/browser/chromeos/login/user_manager.h" 47#include "chrome/browser/chromeos/settings/cros_settings.h" 48#include "chrome/browser/profiles/profile.h" 49#include "chrome/browser/ui/webui/help/help_utils_chromeos.h" 50#include "content/public/browser/browser_thread.h" 51#endif 52 53using base::ListValue; 54using content::BrowserThread; 55 56namespace { 57 58const char kResourceReportIssue[] = "reportAnIssue"; 59 60// Returns the browser version as a string. 61string16 BuildBrowserVersionString() { 62 chrome::VersionInfo version_info; 63 DCHECK(version_info.is_valid()); 64 65 std::string browser_version = version_info.Version(); 66 std::string version_modifier = 67 chrome::VersionInfo::GetVersionStringModifier(); 68 if (!version_modifier.empty()) 69 browser_version += " " + version_modifier; 70 71#if !defined(GOOGLE_CHROME_BUILD) 72 browser_version += " ("; 73 browser_version += version_info.LastChange(); 74 browser_version += ")"; 75#endif 76 77 return UTF8ToUTF16(browser_version); 78} 79 80#if defined(OS_CHROMEOS) 81 82// Returns message that informs user that for update it's better to 83// connect to a network of one of the allowed types. 84string16 GetAllowedConnectionTypesMessage() { 85 if (help_utils_chromeos::IsUpdateOverCellularAllowed()) { 86 return l10n_util::GetStringUTF16(IDS_UPGRADE_NETWORK_LIST_CELLULAR_ALLOWED); 87 } else { 88 return l10n_util::GetStringUTF16( 89 IDS_UPGRADE_NETWORK_LIST_CELLULAR_DISALLOWED); 90 } 91} 92 93bool CanChangeReleaseChannel() { 94 // On non managed machines we have local owner who is the only one to change 95 // anything. 96 if (chromeos::UserManager::Get()->IsCurrentUserOwner()) 97 return true; 98 // On a managed machine we delegate this setting to the users of the same 99 // domain only if the policy value is "domain". 100 if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) { 101 bool value = false; 102 if (!chromeos::CrosSettings::Get()->GetBoolean( 103 chromeos::kReleaseChannelDelegated, &value) || !value) 104 return false; 105 // Get the currently logged in user and strip the domain part only. 106 std::string domain = ""; 107 std::string user = chromeos::UserManager::Get()->GetLoggedInUser()->email(); 108 size_t at_pos = user.find('@'); 109 if (at_pos != std::string::npos && at_pos + 1 < user.length()) 110 domain = user.substr(user.find('@') + 1); 111 return domain == g_browser_process->browser_policy_connector()-> 112 GetEnterpriseDomain(); 113 } 114 return false; 115} 116 117// Pointer to a |StringValue| holding the date of the build date to Chromium 118// OS. Because this value is obtained by reading a file, it is cached here to 119// prevent the need to read from the file system multiple times unnecessarily. 120Value* g_build_date_string = NULL; 121 122#endif // defined(OS_CHROMEOS) 123 124} // namespace 125 126HelpHandler::HelpHandler() 127 : version_updater_(VersionUpdater::Create()), 128 weak_factory_(this) { 129} 130 131HelpHandler::~HelpHandler() { 132} 133 134void HelpHandler::GetLocalizedValues(content::WebUIDataSource* source) { 135 struct L10nResources { 136 const char* name; 137 int ids; 138 }; 139 140 static L10nResources resources[] = { 141 { "helpTitle", IDS_HELP_TITLE }, 142 { "aboutTitle", IDS_ABOUT_TAB_TITLE }, 143#if defined(OS_CHROMEOS) 144 { "aboutProductTitle", IDS_PRODUCT_OS_NAME }, 145#else 146 { "aboutProductTitle", IDS_PRODUCT_NAME }, 147#endif 148 { "aboutProductDescription", IDS_ABOUT_PRODUCT_DESCRIPTION }, 149 { "relaunch", IDS_RELAUNCH_BUTTON }, 150 { "productName", IDS_PRODUCT_NAME }, 151 { "productCopyright", IDS_ABOUT_VERSION_COPYRIGHT }, 152 { "updateCheckStarted", IDS_UPGRADE_CHECK_STARTED }, 153 { "upToDate", IDS_UPGRADE_UP_TO_DATE }, 154 { "updating", IDS_UPGRADE_UPDATING }, 155 { "updateAlmostDone", IDS_UPGRADE_SUCCESSFUL_RELAUNCH }, 156 { "getHelpWithChrome", IDS_GET_HELP_USING_CHROME }, 157 { kResourceReportIssue, IDS_REPORT_AN_ISSUE }, 158#if defined(OS_CHROMEOS) 159 { "platform", IDS_PLATFORM_LABEL }, 160 { "firmware", IDS_ABOUT_PAGE_FIRMWARE }, 161 { "showMoreInfo", IDS_SHOW_MORE_INFO }, 162 { "hideMoreInfo", IDS_HIDE_MORE_INFO }, 163 { "channel", IDS_ABOUT_PAGE_CHANNEL }, 164 { "stable", IDS_ABOUT_PAGE_CHANNEL_STABLE }, 165 { "beta", IDS_ABOUT_PAGE_CHANNEL_BETA }, 166 { "dev", IDS_ABOUT_PAGE_CHANNEL_DEVELOPMENT }, 167 { "channel-changed", IDS_ABOUT_PAGE_CHANNEL_CHANGED }, 168 { "webkit", IDS_WEBKIT }, 169 { "userAgent", IDS_ABOUT_VERSION_USER_AGENT }, 170 { "commandLine", IDS_ABOUT_VERSION_COMMAND_LINE }, 171 { "buildDate", IDS_ABOUT_VERSION_BUILD_DATE }, 172#endif 173#if defined(OS_MACOSX) 174 { "promote", IDS_ABOUT_CHROME_PROMOTE_UPDATER }, 175 { "learnMore", IDS_LEARN_MORE }, 176#endif 177 }; 178 179 if (chrome::UseAlternateSendFeedbackText()) { 180 // Field trial to substitute "Report an Issue" with "Send Feedback". 181 // (crbug.com/169339) 182 std::string report_issue_key(kResourceReportIssue); 183 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(resources); ++i) { 184 if (report_issue_key == resources[i].name) 185 resources[i].ids = IDS_SEND_FEEDBACK; 186 } 187 } 188 189 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(resources); ++i) { 190 source->AddString(resources[i].name, 191 l10n_util::GetStringUTF16(resources[i].ids)); 192 } 193 194 source->AddString( 195 "browserVersion", 196 l10n_util::GetStringFUTF16(IDS_ABOUT_PRODUCT_VERSION, 197 BuildBrowserVersionString())); 198 199 string16 license = l10n_util::GetStringFUTF16( 200 IDS_ABOUT_VERSION_LICENSE, 201 ASCIIToUTF16(chrome::kChromiumProjectURL), 202 ASCIIToUTF16(chrome::kChromeUICreditsURL)); 203 source->AddString("productLicense", license); 204 205#if defined(OS_CHROMEOS) 206 string16 os_license = l10n_util::GetStringFUTF16( 207 IDS_ABOUT_CROS_VERSION_LICENSE, 208 ASCIIToUTF16(chrome::kChromeUIOSCreditsURL)); 209 source->AddString("productOsLicense", os_license); 210#endif 211 212 string16 tos = l10n_util::GetStringFUTF16( 213 IDS_ABOUT_TERMS_OF_SERVICE, UTF8ToUTF16(chrome::kChromeUITermsURL)); 214 source->AddString("productTOS", tos); 215 216 source->AddString("webkitVersion", webkit_glue::GetWebKitVersion()); 217 218 source->AddString("jsEngine", "V8"); 219 source->AddString("jsEngineVersion", v8::V8::GetVersion()); 220 221 source->AddString("userAgentInfo", content::GetUserAgent(GURL())); 222 223 CommandLine::StringType command_line = 224 CommandLine::ForCurrentProcess()->GetCommandLineString(); 225 source->AddString("commandLineInfo", command_line); 226} 227 228void HelpHandler::RegisterMessages() { 229 registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED, 230 content::NotificationService::AllSources()); 231 232 web_ui()->RegisterMessageCallback("onPageLoaded", 233 base::Bind(&HelpHandler::OnPageLoaded, base::Unretained(this))); 234 web_ui()->RegisterMessageCallback("relaunchNow", 235 base::Bind(&HelpHandler::RelaunchNow, base::Unretained(this))); 236 web_ui()->RegisterMessageCallback("openFeedbackDialog", 237 base::Bind(&HelpHandler::OpenFeedbackDialog, base::Unretained(this))); 238 web_ui()->RegisterMessageCallback("openHelpPage", 239 base::Bind(&HelpHandler::OpenHelpPage, base::Unretained(this))); 240#if defined(OS_CHROMEOS) 241 web_ui()->RegisterMessageCallback("setReleaseTrack", 242 base::Bind(&HelpHandler::SetReleaseTrack, base::Unretained(this))); 243#endif 244#if defined(OS_MACOSX) 245 web_ui()->RegisterMessageCallback("promoteUpdater", 246 base::Bind(&HelpHandler::PromoteUpdater, base::Unretained(this))); 247#endif 248} 249 250void HelpHandler::Observe(int type, const content::NotificationSource& source, 251 const content::NotificationDetails& details) { 252 switch (type) { 253 case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: { 254 // A version update is installed and ready to go. Refresh the UI so the 255 // correct state will be shown. 256 version_updater_->CheckForUpdate( 257 base::Bind(&HelpHandler::SetUpdateStatus, base::Unretained(this)) 258#if defined(OS_MACOSX) 259 , base::Bind(&HelpHandler::SetPromotionState, base::Unretained(this)) 260#endif 261 ); 262 break; 263 } 264 default: 265 NOTREACHED(); 266 } 267} 268 269void HelpHandler::OnPageLoaded(const ListValue* args) { 270#if defined(OS_CHROMEOS) 271 // Version information is loaded from a callback 272 loader_.GetVersion( 273 chromeos::VersionLoader::VERSION_FULL, 274 base::Bind(&HelpHandler::OnOSVersion, base::Unretained(this)), 275 &tracker_); 276 loader_.GetFirmware( 277 base::Bind(&HelpHandler::OnOSFirmware, base::Unretained(this)), 278 &tracker_); 279 280 web_ui()->CallJavascriptFunction( 281 "help.HelpPage.updateEnableReleaseChannel", 282 base::FundamentalValue(CanChangeReleaseChannel())); 283 284 if (g_build_date_string == NULL) { 285 // If |g_build_date_string| is |NULL|, the date has not yet been assigned. 286 // Get the date of the last lsb-release file modification. 287 base::FileUtilProxy::GetFileInfo( 288 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 289 base::SysInfo::GetLsbReleaseFilePath(), 290 base::Bind(&HelpHandler::ProcessLsbFileInfo, 291 weak_factory_.GetWeakPtr())); 292 } else { 293 web_ui()->CallJavascriptFunction("help.HelpPage.setBuildDate", 294 *g_build_date_string); 295 } 296#endif // defined(OS_CHROMEOS) 297 298 version_updater_->CheckForUpdate( 299 base::Bind(&HelpHandler::SetUpdateStatus, base::Unretained(this)) 300#if defined(OS_MACOSX) 301 , base::Bind(&HelpHandler::SetPromotionState, base::Unretained(this)) 302#endif 303 ); 304 305#if defined(OS_CHROMEOS) 306 version_updater_->GetReleaseChannel( 307 base::Bind(&HelpHandler::OnReleaseChannel, base::Unretained(this))); 308#endif 309} 310 311#if defined(OS_MACOSX) 312void HelpHandler::PromoteUpdater(const ListValue* args) { 313 version_updater_->PromoteUpdater(); 314} 315#endif 316 317void HelpHandler::RelaunchNow(const ListValue* args) { 318 DCHECK(args->empty()); 319 version_updater_->RelaunchBrowser(); 320} 321 322void HelpHandler::OpenFeedbackDialog(const ListValue* args) { 323 DCHECK(args->empty()); 324 Browser* browser = chrome::FindBrowserWithWebContents( 325 web_ui()->GetWebContents()); 326 chrome::OpenFeedbackDialog(browser); 327} 328 329void HelpHandler::OpenHelpPage(const base::ListValue* args) { 330 DCHECK(args->empty()); 331 Browser* browser = chrome::FindBrowserWithWebContents( 332 web_ui()->GetWebContents()); 333 chrome::ShowHelp(browser, chrome::HELP_SOURCE_WEBUI); 334} 335 336#if defined(OS_CHROMEOS) 337 338void HelpHandler::SetReleaseTrack(const ListValue* args) { 339 if (!CanChangeReleaseChannel()) { 340 LOG(WARNING) << "Non-owner tried to change release track."; 341 return; 342 } 343 344 const std::string channel = UTF16ToUTF8(ExtractStringValue(args)); 345 version_updater_->SetReleaseChannel(channel); 346 // On enterprise machines we can only use SetReleaseChannel to store the 347 // user choice in the lsb-release file but we can not modify the policy blob. 348 // Therefore we only call SetString if the device is locally owned and the 349 // currently logged in user is the owner. 350 if (chromeos::UserManager::Get()->IsCurrentUserOwner()) { 351 chromeos::CrosSettings::Get()->SetString(chromeos::kReleaseChannel, 352 channel); 353 // Check for update after switching release channel. 354 version_updater_->CheckForUpdate(base::Bind(&HelpHandler::SetUpdateStatus, 355 base::Unretained(this))); 356 } 357} 358 359#endif // defined(OS_CHROMEOS) 360 361void HelpHandler::SetUpdateStatus(VersionUpdater::Status status, 362 int progress, const string16& message) { 363 // Only UPDATING state should have progress set. 364 DCHECK(status == VersionUpdater::UPDATING || progress == 0); 365 366 std::string status_str; 367 switch (status) { 368 case VersionUpdater::CHECKING: 369 status_str = "checking"; 370 break; 371 case VersionUpdater::UPDATING: 372 status_str = "updating"; 373 break; 374 case VersionUpdater::NEARLY_UPDATED: 375 status_str = "nearly_updated"; 376 break; 377 case VersionUpdater::UPDATED: 378 status_str = "updated"; 379 break; 380 case VersionUpdater::FAILED: 381 case VersionUpdater::FAILED_OFFLINE: 382 case VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED: 383 status_str = "failed"; 384 break; 385 case VersionUpdater::DISABLED: 386 status_str = "disabled"; 387 break; 388 } 389 390 web_ui()->CallJavascriptFunction("help.HelpPage.setUpdateStatus", 391 base::StringValue(status_str), 392 base::StringValue(message)); 393 394 if (status == VersionUpdater::UPDATING) { 395 web_ui()->CallJavascriptFunction("help.HelpPage.setProgress", 396 base::FundamentalValue(progress)); 397 } 398 399#if defined(OS_CHROMEOS) 400 if (status == VersionUpdater::FAILED_OFFLINE || 401 status == VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED) { 402 string16 types_msg = GetAllowedConnectionTypesMessage(); 403 if (!types_msg.empty()) { 404 web_ui()->CallJavascriptFunction( 405 "help.HelpPage.setAndShowAllowedConnectionTypesMsg", 406 base::StringValue(types_msg)); 407 } else { 408 web_ui()->CallJavascriptFunction( 409 "help.HelpPage.showAllowedConnectionTypesMsg", 410 base::FundamentalValue(false)); 411 } 412 } else { 413 web_ui()->CallJavascriptFunction( 414 "help.HelpPage.showAllowedConnectionTypesMsg", 415 base::FundamentalValue(false)); 416 } 417#endif // defined(OS_CHROMEOS) 418} 419 420#if defined(OS_MACOSX) 421void HelpHandler::SetPromotionState(VersionUpdater::PromotionState state) { 422 std::string state_str; 423 switch (state) { 424 case VersionUpdater::PROMOTE_HIDDEN: 425 state_str = "hidden"; 426 break; 427 case VersionUpdater::PROMOTE_ENABLED: 428 state_str = "enabled"; 429 break; 430 case VersionUpdater::PROMOTE_DISABLED: 431 state_str = "disabled"; 432 break; 433 } 434 435 web_ui()->CallJavascriptFunction("help.HelpPage.setPromotionState", 436 base::StringValue(state_str)); 437} 438#endif // defined(OS_MACOSX) 439 440#if defined(OS_CHROMEOS) 441void HelpHandler::OnOSVersion(const std::string& version) { 442 web_ui()->CallJavascriptFunction("help.HelpPage.setOSVersion", 443 base::StringValue(version)); 444} 445 446void HelpHandler::OnOSFirmware(const std::string& firmware) { 447 web_ui()->CallJavascriptFunction("help.HelpPage.setOSFirmware", 448 base::StringValue(firmware)); 449} 450 451void HelpHandler::OnReleaseChannel(const std::string& channel) { 452 web_ui()->CallJavascriptFunction( 453 "help.HelpPage.updateSelectedChannel", base::StringValue(channel)); 454} 455 456void HelpHandler::ProcessLsbFileInfo( 457 base::PlatformFileError error, const base::PlatformFileInfo& file_info) { 458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 459 460 // If |g_build_date_string| is not |NULL|, then the file's information has 461 // already been retrieved by another tab. 462 if (g_build_date_string == NULL) { 463 base::Time time; 464 if (error == base::PLATFORM_FILE_OK) { 465 // Retrieves the time at which the Chrome OS build was created. 466 // Each time a new build is created, /etc/lsb-release is modified with the 467 // new version numbers of the release. 468 time = file_info.last_modified; 469 } else { 470 // If the time of the build cannot be retrieved, return and do not 471 // display the "Build Date" section. 472 return; 473 } 474 475 // Note that this string will be internationalized. 476 string16 build_date = base::TimeFormatFriendlyDate(time); 477 g_build_date_string = Value::CreateStringValue(build_date); 478 } 479 480 web_ui()->CallJavascriptFunction("help.HelpPage.setBuildDate", 481 *g_build_date_string); 482} 483#endif // defined(OS_CHROMEOS) 484