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/profiles/gaia_info_update_service.h" 6 7 #include "base/command_line.h" 8 #include "base/prefs/pref_service.h" 9 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/chrome_notification_types.h" 11 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/profiles/profile_info_cache.h" 13 #include "chrome/browser/profiles/profile_manager.h" 14 #include "chrome/browser/sync/profile_sync_service.h" 15 #include "chrome/common/chrome_switches.h" 16 #include "chrome/common/pref_names.h" 17 #include "content/public/browser/notification_details.h" 18 #include "third_party/skia/include/core/SkBitmap.h" 19 #include "ui/gfx/image/image.h" 20 21 namespace { 22 23 // Update the user's GAIA info every 24 hours. 24 const int kUpdateIntervalHours = 24; 25 26 // If the users's GAIA info is very out of date then wait at least this long 27 // before starting an update. This avoids slowdown during startup. 28 const int kMinUpdateIntervalSeconds = 5; 29 30 } // namespace 31 32 GAIAInfoUpdateService::GAIAInfoUpdateService(Profile* profile) 33 : profile_(profile) { 34 PrefService* prefs = profile_->GetPrefs(); 35 username_pref_.Init(prefs::kGoogleServicesUsername, prefs, 36 base::Bind(&GAIAInfoUpdateService::OnUsernameChanged, 37 base::Unretained(this))); 38 39 last_updated_ = base::Time::FromInternalValue( 40 prefs->GetInt64(prefs::kProfileGAIAInfoUpdateTime)); 41 ScheduleNextUpdate(); 42 } 43 44 GAIAInfoUpdateService::~GAIAInfoUpdateService() { 45 } 46 47 void GAIAInfoUpdateService::Update() { 48 // The user must be logged in. 49 std::string username = profile_->GetPrefs()->GetString( 50 prefs::kGoogleServicesUsername); 51 if (username.empty()) 52 return; 53 54 if (profile_image_downloader_) 55 return; 56 profile_image_downloader_.reset(new ProfileDownloader(this)); 57 profile_image_downloader_->Start(); 58 } 59 60 // static 61 bool GAIAInfoUpdateService::ShouldUseGAIAProfileInfo(Profile* profile) { 62 #if defined(OS_CHROMEOS) 63 return false; 64 #endif 65 66 // Sync must be allowed. 67 if (!profile->GetOriginalProfile()->IsSyncAccessible()) 68 return false; 69 70 // To enable this feature for testing pass "--google-profile-info". 71 if (CommandLine::ForCurrentProcess()->HasSwitch( 72 switches::kGoogleProfileInfo)) { 73 return true; 74 } 75 76 // This feature is disable by default. 77 return false; 78 } 79 80 bool GAIAInfoUpdateService::NeedsProfilePicture() const { 81 return true; 82 } 83 84 int GAIAInfoUpdateService::GetDesiredImageSideLength() const { 85 return 256; 86 } 87 88 Profile* GAIAInfoUpdateService::GetBrowserProfile() { 89 return profile_; 90 } 91 92 std::string GAIAInfoUpdateService::GetCachedPictureURL() const { 93 return profile_->GetPrefs()->GetString(prefs::kProfileGAIAInfoPictureURL); 94 } 95 96 void GAIAInfoUpdateService::OnProfileDownloadSuccess( 97 ProfileDownloader* downloader) { 98 // Make sure that |ProfileDownloader| gets deleted after return. 99 scoped_ptr<ProfileDownloader> profile_image_downloader( 100 profile_image_downloader_.release()); 101 102 // Save the last updated time. 103 last_updated_ = base::Time::Now(); 104 profile_->GetPrefs()->SetInt64(prefs::kProfileGAIAInfoUpdateTime, 105 last_updated_.ToInternalValue()); 106 ScheduleNextUpdate(); 107 108 base::string16 full_name = downloader->GetProfileFullName(); 109 base::string16 given_name = downloader->GetProfileGivenName(); 110 SkBitmap bitmap = downloader->GetProfilePicture(); 111 ProfileDownloader::PictureStatus picture_status = 112 downloader->GetProfilePictureStatus(); 113 std::string picture_url = downloader->GetProfilePictureURL(); 114 115 ProfileInfoCache& cache = 116 g_browser_process->profile_manager()->GetProfileInfoCache(); 117 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 118 if (profile_index == std::string::npos) 119 return; 120 121 cache.SetGAIANameOfProfileAtIndex(profile_index, full_name); 122 cache.SetGAIAGivenNameOfProfileAtIndex(profile_index, given_name); 123 124 // The profile index may have changed. 125 profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 126 if (profile_index == std::string::npos) 127 return; 128 if (picture_status == ProfileDownloader::PICTURE_SUCCESS) { 129 profile_->GetPrefs()->SetString(prefs::kProfileGAIAInfoPictureURL, 130 picture_url); 131 gfx::Image gfx_image = gfx::Image::CreateFrom1xBitmap(bitmap); 132 cache.SetGAIAPictureOfProfileAtIndex(profile_index, &gfx_image); 133 } else if (picture_status == ProfileDownloader::PICTURE_DEFAULT) { 134 cache.SetGAIAPictureOfProfileAtIndex(profile_index, NULL); 135 } 136 137 // If this profile hasn't switched to using GAIA information for the profile 138 // name and picture then switch it now. Once the profile has switched this 139 // preference guards against clobbering the user's custom settings. 140 if (!cache.GetHasMigratedToGAIAInfoOfProfileAtIndex(profile_index)) { 141 cache.SetHasMigratedToGAIAInfoOfProfileAtIndex(profile_index, true); 142 // Order matters here for shortcut management, like in 143 // ProfileShortcutManagerWin::OnProfileAdded, as the picture update does not 144 // allow us to change the target, so we have to apply any renaming first. We 145 // also need to re-fetch the index, as SetIsUsingGAIANameOfProfileAtIndex 146 // may alter it. 147 cache.SetIsUsingGAIANameOfProfileAtIndex(profile_index, true); 148 profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 149 cache.SetIsUsingGAIAPictureOfProfileAtIndex(profile_index, true); 150 } 151 } 152 153 void GAIAInfoUpdateService::OnProfileDownloadFailure( 154 ProfileDownloader* downloader, 155 ProfileDownloaderDelegate::FailureReason reason) { 156 profile_image_downloader_.reset(); 157 158 // Save the last updated time. 159 last_updated_ = base::Time::Now(); 160 profile_->GetPrefs()->SetInt64(prefs::kProfileGAIAInfoUpdateTime, 161 last_updated_.ToInternalValue()); 162 ScheduleNextUpdate(); 163 } 164 165 void GAIAInfoUpdateService::OnUsernameChanged() { 166 ProfileInfoCache& cache = 167 g_browser_process->profile_manager()->GetProfileInfoCache(); 168 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 169 if (profile_index == std::string::npos) 170 return; 171 172 std::string username = profile_->GetPrefs()->GetString( 173 prefs::kGoogleServicesUsername); 174 if (username.empty()) { 175 // Unset the old user's GAIA info. 176 cache.SetGAIANameOfProfileAtIndex(profile_index, base::string16()); 177 // The profile index may have changed. 178 profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 179 if (profile_index == std::string::npos) 180 return; 181 cache.SetGAIAPictureOfProfileAtIndex(profile_index, NULL); 182 // Unset the cached URL. 183 profile_->GetPrefs()->ClearPref(prefs::kProfileGAIAInfoPictureURL); 184 } else { 185 // Update the new user's GAIA info. 186 Update(); 187 } 188 } 189 190 void GAIAInfoUpdateService::ScheduleNextUpdate() { 191 if (timer_.IsRunning()) 192 return; 193 194 const base::TimeDelta desired_delta = 195 base::TimeDelta::FromHours(kUpdateIntervalHours); 196 const base::TimeDelta update_delta = base::Time::Now() - last_updated_; 197 198 base::TimeDelta delta; 199 if (update_delta < base::TimeDelta() || update_delta > desired_delta) 200 delta = base::TimeDelta::FromSeconds(kMinUpdateIntervalSeconds); 201 else 202 delta = desired_delta - update_delta; 203 204 timer_.Start(FROM_HERE, delta, this, &GAIAInfoUpdateService::Update); 205 } 206