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/ntp/ntp_login_handler.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/metrics/histogram.h" 12#include "base/prefs/pref_notifier.h" 13#include "base/prefs/pref_service.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/chrome_notification_types.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/browser/profiles/profile_info_cache.h" 20#include "chrome/browser/profiles/profile_manager.h" 21#include "chrome/browser/profiles/profile_metrics.h" 22#include "chrome/browser/signin/signin_manager.h" 23#include "chrome/browser/signin/signin_manager_factory.h" 24#include "chrome/browser/signin/signin_promo.h" 25#include "chrome/browser/sync/profile_sync_service.h" 26#include "chrome/browser/sync/profile_sync_service_factory.h" 27#include "chrome/browser/ui/browser.h" 28#include "chrome/browser/ui/browser_finder.h" 29#include "chrome/browser/ui/browser_window.h" 30#include "chrome/browser/ui/chrome_pages.h" 31#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 32#include "chrome/browser/web_resource/promo_resource_service.h" 33#include "chrome/common/pref_names.h" 34#include "chrome/common/url_constants.h" 35#include "content/public/browser/notification_details.h" 36#include "content/public/browser/notification_service.h" 37#include "content/public/browser/web_contents.h" 38#include "content/public/browser/web_ui.h" 39#include "content/public/common/page_zoom.h" 40#include "grit/chromium_strings.h" 41#include "grit/generated_resources.h" 42#include "net/base/escape.h" 43#include "skia/ext/image_operations.h" 44#include "ui/base/l10n/l10n_util.h" 45#include "ui/base/webui/web_ui_util.h" 46#include "ui/gfx/canvas.h" 47#include "ui/gfx/image/image.h" 48 49using content::OpenURLParams; 50using content::Referrer; 51 52namespace { 53 54SkBitmap GetGAIAPictureForNTP(const gfx::Image& image) { 55 // This value must match the width and height value of login-status-icon 56 // in new_tab.css. 57 const int kLength = 27; 58 SkBitmap bmp = skia::ImageOperations::Resize(*image.ToSkBitmap(), 59 skia::ImageOperations::RESIZE_BEST, kLength, kLength); 60 61 gfx::Canvas canvas(gfx::Size(kLength, kLength), 1.0f, false); 62 canvas.DrawImageInt(gfx::ImageSkia::CreateFrom1xBitmap(bmp), 0, 0); 63 64 // Draw a gray border on the inside of the icon. 65 SkColor color = SkColorSetARGB(83, 0, 0, 0); 66 canvas.DrawRect(gfx::Rect(0, 0, kLength - 1, kLength - 1), color); 67 68 return canvas.ExtractImageRep().sk_bitmap(); 69} 70 71// Puts the |content| into a span with the given CSS class. 72base::string16 CreateSpanWithClass(const base::string16& content, 73 const std::string& css_class) { 74 return ASCIIToUTF16("<span class='" + css_class + "'>") + 75 net::EscapeForHTML(content) + ASCIIToUTF16("</span>"); 76} 77 78} // namespace 79 80NTPLoginHandler::NTPLoginHandler() { 81} 82 83NTPLoginHandler::~NTPLoginHandler() { 84} 85 86void NTPLoginHandler::RegisterMessages() { 87 PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs(); 88 username_pref_.Init(prefs::kGoogleServicesUsername, 89 pref_service, 90 base::Bind(&NTPLoginHandler::UpdateLogin, 91 base::Unretained(this))); 92 signin_allowed_pref_.Init(prefs::kSigninAllowed, 93 pref_service, 94 base::Bind(&NTPLoginHandler::UpdateLogin, 95 base::Unretained(this))); 96 97 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, 98 content::NotificationService::AllSources()); 99 100 web_ui()->RegisterMessageCallback("initializeSyncLogin", 101 base::Bind(&NTPLoginHandler::HandleInitializeSyncLogin, 102 base::Unretained(this))); 103 web_ui()->RegisterMessageCallback("showSyncLoginUI", 104 base::Bind(&NTPLoginHandler::HandleShowSyncLoginUI, 105 base::Unretained(this))); 106 web_ui()->RegisterMessageCallback("loginMessageSeen", 107 base::Bind(&NTPLoginHandler::HandleLoginMessageSeen, 108 base::Unretained(this))); 109 web_ui()->RegisterMessageCallback("showAdvancedLoginUI", 110 base::Bind(&NTPLoginHandler::HandleShowAdvancedLoginUI, 111 base::Unretained(this))); 112} 113 114void NTPLoginHandler::Observe(int type, 115 const content::NotificationSource& source, 116 const content::NotificationDetails& details) { 117 if (type == chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED) { 118 UpdateLogin(); 119 } else { 120 NOTREACHED(); 121 } 122} 123 124void NTPLoginHandler::HandleInitializeSyncLogin(const ListValue* args) { 125 UpdateLogin(); 126} 127 128void NTPLoginHandler::HandleShowSyncLoginUI(const ListValue* args) { 129 Profile* profile = Profile::FromWebUI(web_ui()); 130 std::string username = profile->GetPrefs()->GetString( 131 prefs::kGoogleServicesUsername); 132 content::WebContents* web_contents = web_ui()->GetWebContents(); 133 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); 134 if (!browser) 135 return; 136 137 if (username.empty()) { 138#if !defined(OS_ANDROID) 139 // The user isn't signed in, show the sign in promo. 140 if (signin::ShouldShowPromo(profile)) { 141 signin::Source source = 142 (web_contents->GetURL().spec() == chrome::kChromeUIAppsURL) ? 143 signin::SOURCE_APPS_PAGE_LINK : 144 signin::SOURCE_NTP_LINK; 145 chrome::ShowBrowserSignin(browser, source); 146 RecordInHistogram(NTP_SIGN_IN_PROMO_CLICKED); 147 } 148#endif 149 } else if (args->GetSize() == 4) { 150 // The user is signed in, show the profiles menu. 151 double x = 0; 152 double y = 0; 153 double width = 0; 154 double height = 0; 155 bool success = args->GetDouble(0, &x); 156 DCHECK(success); 157 success = args->GetDouble(1, &y); 158 DCHECK(success); 159 success = args->GetDouble(2, &width); 160 DCHECK(success); 161 success = args->GetDouble(3, &height); 162 DCHECK(success); 163 164 double zoom = content::ZoomLevelToZoomFactor(web_contents->GetZoomLevel()); 165 gfx::Rect rect(x * zoom, y * zoom, width * zoom, height * zoom); 166 167 browser->window()->ShowAvatarBubble(web_ui()->GetWebContents(), rect); 168 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::NTP_AVATAR_BUBBLE); 169 } 170} 171 172void NTPLoginHandler::RecordInHistogram(int type) { 173 // Invalid type to record. 174 if (type < NTP_SIGN_IN_PROMO_VIEWED || 175 type > NTP_SIGN_IN_PROMO_CLICKED) { 176 NOTREACHED(); 177 } else { 178 UMA_HISTOGRAM_ENUMERATION("SyncPromo.NTPPromo", type, 179 NTP_SIGN_IN_PROMO_BUCKET_BOUNDARY); 180 } 181} 182 183void NTPLoginHandler::HandleLoginMessageSeen(const ListValue* args) { 184 Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean( 185 prefs::kSignInPromoShowNTPBubble, false); 186 NewTabUI* ntp_ui = NewTabUI::FromWebUIController(web_ui()->GetController()); 187 // When instant extended is enabled, there may not be a NewTabUI object. 188 if (ntp_ui) 189 ntp_ui->set_showing_sync_bubble(true); 190} 191 192void NTPLoginHandler::HandleShowAdvancedLoginUI(const ListValue* args) { 193 Browser* browser = 194 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); 195 if (browser) 196 chrome::ShowBrowserSignin(browser, signin::SOURCE_NTP_LINK); 197} 198 199void NTPLoginHandler::UpdateLogin() { 200 Profile* profile = Profile::FromWebUI(web_ui()); 201 std::string username = profile->GetPrefs()->GetString( 202 prefs::kGoogleServicesUsername); 203 204 base::string16 header, sub_header; 205 std::string icon_url; 206 if (!username.empty()) { 207 ProfileInfoCache& cache = 208 g_browser_process->profile_manager()->GetProfileInfoCache(); 209 size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath()); 210 if (profile_index != std::string::npos) { 211 // Only show the profile picture and full name for the single profile 212 // case. In the multi-profile case the profile picture is visible in the 213 // title bar and the full name can be ambiguous. 214 if (cache.GetNumberOfProfiles() == 1) { 215 base::string16 name = cache.GetGAIANameOfProfileAtIndex(profile_index); 216 if (!name.empty()) 217 header = CreateSpanWithClass(name, "profile-name"); 218 const gfx::Image* image = 219 cache.GetGAIAPictureOfProfileAtIndex(profile_index); 220 if (image) 221 icon_url = webui::GetBitmapDataUrl(GetGAIAPictureForNTP(*image)); 222 } 223 if (header.empty()) 224 header = CreateSpanWithClass(UTF8ToUTF16(username), "profile-name"); 225 } 226 } else { 227#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) 228 // Android uses a custom sign in promo. Don't call the function 229 // signin::ShouldShowPromo() since it does a bunch of checks that are not 230 // required here. We only want to suppress this login status for users that 231 // are not allowed to sign in. Chromeos does not show this status header 232 // at all. 233 SigninManager* signin = SigninManagerFactory::GetForProfile( 234 profile->GetOriginalProfile()); 235 if (!profile->IsManaged() && signin->IsSigninAllowed()) { 236 base::string16 signed_in_link = l10n_util::GetStringUTF16( 237 IDS_SYNC_PROMO_NOT_SIGNED_IN_STATUS_LINK); 238 signed_in_link = CreateSpanWithClass(signed_in_link, "link-span"); 239 header = l10n_util::GetStringFUTF16( 240 IDS_SYNC_PROMO_NOT_SIGNED_IN_STATUS_HEADER, 241 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); 242 sub_header = l10n_util::GetStringFUTF16( 243 IDS_SYNC_PROMO_NOT_SIGNED_IN_STATUS_SUB_HEADER, signed_in_link); 244 // Record that the user was shown the promo. 245 RecordInHistogram(NTP_SIGN_IN_PROMO_VIEWED); 246 } 247#endif 248 } 249 250 StringValue header_value(header); 251 StringValue sub_header_value(sub_header); 252 StringValue icon_url_value(icon_url); 253 base::FundamentalValue is_user_signed_in(!username.empty()); 254 web_ui()->CallJavascriptFunction("ntp.updateLogin", 255 header_value, sub_header_value, icon_url_value, is_user_signed_in); 256} 257 258// static 259bool NTPLoginHandler::ShouldShow(Profile* profile) { 260#if defined(OS_CHROMEOS) 261 // For now we don't care about showing sync status on Chrome OS. The promo 262 // UI and the avatar menu don't exist on that platform. 263 return false; 264#else 265 SigninManager* signin = SigninManagerFactory::GetForProfile(profile); 266 return !profile->IsOffTheRecord() && signin && signin->IsSigninAllowed(); 267#endif 268} 269 270// static 271void NTPLoginHandler::GetLocalizedValues(Profile* profile, 272 DictionaryValue* values) { 273 PrefService* prefs = profile->GetPrefs(); 274 bool hide_sync = !prefs->GetBoolean(prefs::kSignInPromoShowNTPBubble); 275 276 base::string16 message = hide_sync ? base::string16() : 277 l10n_util::GetStringFUTF16(IDS_SYNC_PROMO_NTP_BUBBLE_MESSAGE, 278 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); 279 280 values->SetString("login_status_message", message); 281 values->SetString("login_status_url", 282 hide_sync ? std::string() : chrome::kSyncLearnMoreURL); 283 values->SetString("login_status_advanced", 284 hide_sync ? base::string16() : 285 l10n_util::GetStringUTF16(IDS_SYNC_PROMO_NTP_BUBBLE_ADVANCED)); 286 values->SetString("login_status_dismiss", 287 hide_sync ? base::string16() : 288 l10n_util::GetStringUTF16(IDS_SYNC_PROMO_NTP_BUBBLE_OK)); 289} 290