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/prefs/pref_service.h" 8 #include "chrome/browser/browser_process.h" 9 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile_info_cache.h" 12 #include "chrome/browser/profiles/profile_manager.h" 13 #include "chrome/browser/signin/signin_manager_factory.h" 14 #include "chrome/browser/sync/profile_sync_service.h" 15 #include "chrome/common/pref_names.h" 16 #include "components/signin/core/common/profile_management_switches.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 SigninManagerBase* signin_manager = 35 SigninManagerFactory::GetForProfile(profile_); 36 signin_manager->AddObserver(this); 37 38 PrefService* prefs = profile_->GetPrefs(); 39 last_updated_ = base::Time::FromInternalValue( 40 prefs->GetInt64(prefs::kProfileGAIAInfoUpdateTime)); 41 ScheduleNextUpdate(); 42 } 43 44 GAIAInfoUpdateService::~GAIAInfoUpdateService() { 45 DCHECK(!profile_) << "Shutdown not called before dtor"; 46 } 47 48 void GAIAInfoUpdateService::Update() { 49 // The user must be logged in. 50 SigninManagerBase* signin_manager = 51 SigninManagerFactory::GetForProfile(profile_); 52 if (!signin_manager->IsAuthenticated()) 53 return; 54 55 if (profile_image_downloader_) 56 return; 57 profile_image_downloader_.reset(new ProfileDownloader(this)); 58 profile_image_downloader_->Start(); 59 } 60 61 // static 62 bool GAIAInfoUpdateService::ShouldUseGAIAProfileInfo(Profile* profile) { 63 #if defined(OS_CHROMEOS) 64 return false; 65 #endif 66 67 // Sync must be allowed. 68 if (!profile->GetOriginalProfile()->IsSyncAccessible()) 69 return false; 70 71 // To enable this feature for testing pass "--google-profile-info". 72 if (switches::IsGoogleProfileInfo()) 73 return true; 74 75 // This feature is disable by default. 76 return false; 77 } 78 79 bool GAIAInfoUpdateService::NeedsProfilePicture() const { 80 return true; 81 } 82 83 int GAIAInfoUpdateService::GetDesiredImageSideLength() const { 84 return 256; 85 } 86 87 Profile* GAIAInfoUpdateService::GetBrowserProfile() { 88 return profile_; 89 } 90 91 std::string GAIAInfoUpdateService::GetCachedPictureURL() const { 92 return profile_->GetPrefs()->GetString(prefs::kProfileGAIAInfoPictureURL); 93 } 94 95 void GAIAInfoUpdateService::OnProfileDownloadSuccess( 96 ProfileDownloader* downloader) { 97 // Make sure that |ProfileDownloader| gets deleted after return. 98 scoped_ptr<ProfileDownloader> profile_image_downloader( 99 profile_image_downloader_.release()); 100 101 // Save the last updated time. 102 last_updated_ = base::Time::Now(); 103 profile_->GetPrefs()->SetInt64(prefs::kProfileGAIAInfoUpdateTime, 104 last_updated_.ToInternalValue()); 105 ScheduleNextUpdate(); 106 107 base::string16 full_name = downloader->GetProfileFullName(); 108 base::string16 given_name = downloader->GetProfileGivenName(); 109 SkBitmap bitmap = downloader->GetProfilePicture(); 110 ProfileDownloader::PictureStatus picture_status = 111 downloader->GetProfilePictureStatus(); 112 std::string picture_url = downloader->GetProfilePictureURL(); 113 114 ProfileInfoCache& cache = 115 g_browser_process->profile_manager()->GetProfileInfoCache(); 116 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 117 if (profile_index == std::string::npos) 118 return; 119 120 cache.SetGAIANameOfProfileAtIndex(profile_index, full_name); 121 // The profile index may have changed. 122 profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 123 DCHECK_NE(profile_index, std::string::npos); 124 125 cache.SetGAIAGivenNameOfProfileAtIndex(profile_index, given_name); 126 // The profile index may have changed. 127 profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 128 DCHECK_NE(profile_index, std::string::npos); 129 130 if (picture_status == ProfileDownloader::PICTURE_SUCCESS) { 131 profile_->GetPrefs()->SetString(prefs::kProfileGAIAInfoPictureURL, 132 picture_url); 133 gfx::Image gfx_image = gfx::Image::CreateFrom1xBitmap(bitmap); 134 cache.SetGAIAPictureOfProfileAtIndex(profile_index, &gfx_image); 135 } else if (picture_status == ProfileDownloader::PICTURE_DEFAULT) { 136 cache.SetGAIAPictureOfProfileAtIndex(profile_index, NULL); 137 } 138 } 139 140 void GAIAInfoUpdateService::OnProfileDownloadFailure( 141 ProfileDownloader* downloader, 142 ProfileDownloaderDelegate::FailureReason reason) { 143 profile_image_downloader_.reset(); 144 145 // Save the last updated time. 146 last_updated_ = base::Time::Now(); 147 profile_->GetPrefs()->SetInt64(prefs::kProfileGAIAInfoUpdateTime, 148 last_updated_.ToInternalValue()); 149 ScheduleNextUpdate(); 150 } 151 152 void GAIAInfoUpdateService::OnUsernameChanged(const std::string& username) { 153 ProfileInfoCache& cache = 154 g_browser_process->profile_manager()->GetProfileInfoCache(); 155 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 156 if (profile_index == std::string::npos) 157 return; 158 159 if (username.empty()) { 160 // Unset the old user's GAIA info. 161 cache.SetGAIANameOfProfileAtIndex(profile_index, base::string16()); 162 cache.SetGAIAGivenNameOfProfileAtIndex(profile_index, base::string16()); 163 // The profile index may have changed. 164 profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); 165 if (profile_index == std::string::npos) 166 return; 167 cache.SetGAIAPictureOfProfileAtIndex(profile_index, NULL); 168 // Unset the cached URL. 169 profile_->GetPrefs()->ClearPref(prefs::kProfileGAIAInfoPictureURL); 170 } else { 171 // Update the new user's GAIA info. 172 Update(); 173 } 174 } 175 176 void GAIAInfoUpdateService::Shutdown() { 177 timer_.Stop(); 178 profile_image_downloader_.reset(); 179 SigninManagerBase* signin_manager = 180 SigninManagerFactory::GetForProfile(profile_); 181 signin_manager->RemoveObserver(this); 182 183 // OK to reset |profile_| pointer here because GAIAInfoUpdateService will not 184 // access it again. This pointer is also used to implement the delegate for 185 // |profile_image_downloader_|. However that object was destroyed above. 186 profile_ = NULL; 187 } 188 189 void GAIAInfoUpdateService::ScheduleNextUpdate() { 190 if (timer_.IsRunning()) 191 return; 192 193 const base::TimeDelta desired_delta = 194 base::TimeDelta::FromHours(kUpdateIntervalHours); 195 const base::TimeDelta update_delta = base::Time::Now() - last_updated_; 196 197 base::TimeDelta delta; 198 if (update_delta < base::TimeDelta() || update_delta > desired_delta) 199 delta = base::TimeDelta::FromSeconds(kMinUpdateIntervalSeconds); 200 else 201 delta = desired_delta - update_delta; 202 203 timer_.Start(FROM_HERE, delta, this, &GAIAInfoUpdateService::Update); 204 } 205 206 void GAIAInfoUpdateService::GoogleSigninSucceeded( 207 const std::string& account_id, 208 const std::string& username, 209 const std::string& password) { 210 OnUsernameChanged(username); 211 } 212 213 void GAIAInfoUpdateService::GoogleSignedOut(const std::string& account_id, 214 const std::string& username) { 215 OnUsernameChanged(std::string()); 216 } 217