From 6d33da172efea858a707202dc89eb3b04c7d0638 Mon Sep 17 00:00:00 2001 From: "sail@chromium.org" Date: Tue, 22 Nov 2011 03:56:09 +0000 Subject: Make ProfileImageDownloader available to non-chromeos code BUG=91241 TEST= Review URL: http://codereview.chromium.org/8510069 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111098 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/chromeos/login/captcha_view.h | 2 +- chrome/browser/chromeos/login/image_decoder.cc | 68 ----- chrome/browser/chromeos/login/image_decoder.h | 66 ----- chrome/browser/chromeos/login/image_downloader.h | 2 +- .../chromeos/login/login_utils_browsertest.cc | 1 + .../chromeos/login/profile_image_downloader.cc | 297 -------------------- .../chromeos/login/profile_image_downloader.h | 97 ------- chrome/browser/chromeos/login/user_image_loader.cc | 1 - chrome/browser/chromeos/login/user_image_loader.h | 2 +- chrome/browser/chromeos/login/user_manager.cc | 119 ++++---- chrome/browser/chromeos/login/user_manager.h | 16 +- chrome/browser/image_decoder.cc | 64 +++++ chrome/browser/image_decoder.h | 62 +++++ chrome/browser/profiles/profile_downloader.cc | 305 +++++++++++++++++++++ chrome/browser/profiles/profile_downloader.h | 83 ++++++ .../browser/profiles/profile_downloader_delegate.h | 36 +++ chrome/chrome_browser.gypi | 9 +- 17 files changed, 637 insertions(+), 593 deletions(-) delete mode 100644 chrome/browser/chromeos/login/image_decoder.cc delete mode 100644 chrome/browser/chromeos/login/image_decoder.h delete mode 100644 chrome/browser/chromeos/login/profile_image_downloader.cc delete mode 100644 chrome/browser/chromeos/login/profile_image_downloader.h create mode 100644 chrome/browser/image_decoder.cc create mode 100644 chrome/browser/image_decoder.h create mode 100644 chrome/browser/profiles/profile_downloader.cc create mode 100644 chrome/browser/profiles/profile_downloader.h create mode 100644 chrome/browser/profiles/profile_downloader_delegate.h diff --git a/chrome/browser/chromeos/login/captcha_view.h b/chrome/browser/chromeos/login/captcha_view.h index 3122bc7..0ef4c57 100644 --- a/chrome/browser/chromeos/login/captcha_view.h +++ b/chrome/browser/chromeos/login/captcha_view.h @@ -8,7 +8,7 @@ #include -#include "chrome/browser/chromeos/login/image_decoder.h" +#include "chrome/browser/image_decoder.h" #include "googleurl/src/gurl.h" #include "ui/views/window/dialog_delegate.h" #include "views/controls/button/button.h" diff --git a/chrome/browser/chromeos/login/image_decoder.cc b/chrome/browser/chromeos/login/image_decoder.cc deleted file mode 100644 index 87671c2..0000000 --- a/chrome/browser/chromeos/login/image_decoder.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 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/chromeos/login/image_decoder.h" - -#include "base/bind.h" -#include "chrome/browser/browser_process.h" -#include "chrome/common/chrome_utility_messages.h" -#include "content/public/browser/browser_thread.h" - -using content::BrowserThread; - -namespace chromeos { - -ImageDecoder::ImageDecoder(Delegate* delegate, - const std::string& image_data) - : delegate_(delegate), - image_data_(image_data.begin(), image_data.end()), - target_thread_id_(BrowserThread::UI) { -} - -ImageDecoder::~ImageDecoder() {} - -void ImageDecoder::Start() { - if (!BrowserThread::GetCurrentThreadIdentifier(&target_thread_id_)) { - NOTREACHED(); - return; - } - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&ImageDecoder::DecodeImageInSandbox, this, image_data_)); -} - -bool ImageDecoder::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ImageDecoder, message) - IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded, - OnDecodeImageSucceeded) - IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed, - OnDecodeImageFailed) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void ImageDecoder::OnDecodeImageSucceeded(const SkBitmap& decoded_image) { - DCHECK(BrowserThread::CurrentlyOn(target_thread_id_)); - if (delegate_) - delegate_->OnImageDecoded(this, decoded_image); -} - -void ImageDecoder::OnDecodeImageFailed() { - DCHECK(BrowserThread::CurrentlyOn(target_thread_id_)); - if (delegate_) - delegate_->OnDecodeImageFailed(this); -} - -void ImageDecoder::DecodeImageInSandbox( - const std::vector& image_data) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - UtilityProcessHost* utility_process_host = - new UtilityProcessHost(this, - target_thread_id_); - utility_process_host->Send(new ChromeUtilityMsg_DecodeImage(image_data)); -} - -} // namespace chromeos diff --git a/chrome/browser/chromeos/login/image_decoder.h b/chrome/browser/chromeos/login/image_decoder.h deleted file mode 100644 index c60f248..0000000 --- a/chrome/browser/chromeos/login/image_decoder.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_IMAGE_DECODER_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_IMAGE_DECODER_H_ -#pragma once - -#include -#include - -#include "content/browser/utility_process_host.h" - -class SkBitmap; - -namespace chromeos { - -// Decodes an image in a sandboxed process. -class ImageDecoder : public UtilityProcessHost::Client { - public: - class Delegate { - public: - // Called when image is decoded. - // |decoder| is used to identify the image in case of decoding several - // images simultaneously. - virtual void OnImageDecoded(const ImageDecoder* decoder, - const SkBitmap& decoded_image) = 0; - - // Called when decoding image failed. Delegate can do some cleanup in - // this handler. - virtual void OnDecodeImageFailed(const ImageDecoder* decoder) {} - - protected: - virtual ~Delegate() {} - }; - - ImageDecoder(Delegate* delegate, - const std::string& image_data); - - // Starts image decoding. - void Start(); - - private: - // It's a reference counted object, so destructor is private. - virtual ~ImageDecoder(); - - // Overidden from UtilityProcessHost::Client: - virtual bool OnMessageReceived(const IPC::Message& message); - - // IPC message handlers. - void OnDecodeImageSucceeded(const SkBitmap& decoded_image); - void OnDecodeImageFailed(); - - // Launches sandboxed process that will decode the image. - void DecodeImageInSandbox(const std::vector& image_data); - - Delegate* delegate_; - std::vector image_data_; - content::BrowserThread::ID target_thread_id_; - - DISALLOW_COPY_AND_ASSIGN(ImageDecoder); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_IMAGE_DECODER_H_ diff --git a/chrome/browser/chromeos/login/image_downloader.h b/chrome/browser/chromeos/login/image_downloader.h index 4fd61ca..02b1f84 100644 --- a/chrome/browser/chromeos/login/image_downloader.h +++ b/chrome/browser/chromeos/login/image_downloader.h @@ -10,7 +10,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" -#include "chrome/browser/chromeos/login/image_decoder.h" +#include "chrome/browser/image_decoder.h" #include "content/public/common/url_fetcher_delegate.h" #include "googleurl/src/gurl.h" diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc index 8f66f66..85b15a4 100644 --- a/chrome/browser/chromeos/login/login_utils_browsertest.cc +++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc @@ -30,6 +30,7 @@ #include "chrome/common/net/gaia/gaia_auth_consumer.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_pref_service.h" +#include "content/public/common/url_fetcher_delegate.h" #include "content/test/test_browser_thread.h" #include "content/test/test_url_fetcher_factory.h" #include "net/url_request/url_request.h" diff --git a/chrome/browser/chromeos/login/profile_image_downloader.cc b/chrome/browser/chromeos/login/profile_image_downloader.cc deleted file mode 100644 index 475d948..0000000 --- a/chrome/browser/chromeos/login/profile_image_downloader.cc +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2011 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/chromeos/login/profile_image_downloader.h" - -#include -#include - -#include "base/json/json_reader.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/string_split.h" -#include "base/string_util.h" -#include "base/stringprintf.h" -#include "chrome/browser/chromeos/login/helper.h" -#include "chrome/browser/chromeos/login/user_manager.h" -#include "chrome/browser/net/gaia/token_service.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/common/chrome_notification_types.h" -#include "chrome/common/net/gaia/gaia_constants.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" -#include "content/public/common/url_fetcher.h" -#include "googleurl/src/gurl.h" -#include "skia/ext/image_operations.h" - -using content::BrowserThread; - -namespace chromeos { - -namespace { - -// Template for optional authorization header. -const char kAuthorizationHeader[] = "Authorization: GoogleLogin auth=%s"; - -// URL requesting Picasa API for user info. -const char kUserEntryURL[] = - "http://picasaweb.google.com/data/entry/api/user/default?alt=json"; -// Path in JSON dictionary to user's photo thumbnail URL. -const char kPhotoThumbnailURLPath[] = "entry.gphoto$thumbnail.$t"; -// Path format for specifying thumbnail's size. -const char kThumbnailSizeFormat[] = "s%d-c"; -// Default Picasa thumbnail size. -const int kDefaultThumbnailSize = 64; - -// Separator of URL path components. -const char kURLPathSeparator = '/'; - -// Photo ID of the Picasa Web Albums profile picture (base64 of 0). -const char kPicasaPhotoId[] = "AAAAAAAAAAA"; - -// Photo version of the default PWA profile picture (base64 of 1). -const char kDefaultPicasaPhotoVersion[] = "AAAAAAAAAAE"; - -// Photo ID of the Google+ profile picture (base64 of 2). -const char kGooglePlusPhotoId[] = "AAAAAAAAAAI"; - -// Photo version of the default Google+ profile picture (base64 of 0). -const char kDefaultGooglePlusPhotoVersion[] = "AAAAAAAAAAA"; - -// Number of path components in profile picture URL. -const size_t kProfileImageURLPathComponentsCount = 7; - -// Index of path component with photo ID. -const int kPhotoIdPathComponentIndex = 2; - -// Index of path component with photo version. -const int kPhotoVersionPathComponentIndex = 3; - -} // namespace - -std::string ProfileImageDownloader::GetProfileImageURL( - const std::string& data) const { - int error_code = -1; - std::string error_message; - scoped_ptr root_value(base::JSONReader::ReadAndReturnError( - data, false, &error_code, &error_message)); - if (!root_value.get()) { - LOG(ERROR) << "Error while parsing Picasa user entry response: " - << error_message; - return std::string(); - } - if (!root_value->IsType(base::Value::TYPE_DICTIONARY)) { - LOG(ERROR) << "JSON root is not a dictionary: " - << root_value->GetType(); - return std::string(); - } - base::DictionaryValue* root_dictionary = - static_cast(root_value.get()); - - std::string thumbnail_url_string; - if (!root_dictionary->GetString( - kPhotoThumbnailURLPath, &thumbnail_url_string)) { - LOG(ERROR) << "Can't find thumbnail path in JSON data: " - << data; - return std::string(); - } - - // Try to change the size of thumbnail we are going to get. - // Typical URL looks like this: - // http://lh0.ggpht.com/-abcd1aBCDEf/AAAA/AAA_A/abc12/s64-c/1234567890.jpg - std::string default_thumbnail_size_path_component( - base::StringPrintf(kThumbnailSizeFormat, kDefaultThumbnailSize)); - std::string new_thumbnail_size_path_component( - base::StringPrintf(kThumbnailSizeFormat, login::kUserImageSize)); - size_t thumbnail_size_pos = - thumbnail_url_string.find(default_thumbnail_size_path_component); - if (thumbnail_size_pos != std::string::npos) { - size_t thumbnail_size_end = - thumbnail_size_pos + default_thumbnail_size_path_component.size(); - thumbnail_url_string = - thumbnail_url_string.substr(0, thumbnail_size_pos) + - new_thumbnail_size_path_component + - thumbnail_url_string.substr( - thumbnail_size_end, - thumbnail_url_string.size() - thumbnail_size_end); - } else { - LOG(WARNING) << "Hasn't found thumbnail size part in image URL: " - << thumbnail_url_string; - // Use the thumbnail URL we have. - } - - GURL thumbnail_url(thumbnail_url_string); - if (!thumbnail_url.is_valid()) { - LOG(ERROR) << "Thumbnail URL is not valid: " << thumbnail_url_string; - return std::string(); - } - return thumbnail_url.spec(); -} - -bool ProfileImageDownloader::IsDefaultProfileImageURL( - const std::string& url) const { - - GURL image_url_object(url); - DCHECK(image_url_object.is_valid()); - VLOG(1) << "URL to check for default image: " << image_url_object.spec(); - std::vector path_components; - base::SplitString(image_url_object.path(), - kURLPathSeparator, - &path_components); - - if (path_components.size() != kProfileImageURLPathComponentsCount) - return false; - - const std::string& photo_id = path_components[kPhotoIdPathComponentIndex]; - const std::string& photo_version = - path_components[kPhotoVersionPathComponentIndex]; - - // There are at least two pairs of (ID, version) for the default photo: - // the default Google+ profile photo and the default Picasa profile photo. - return ((photo_id == kPicasaPhotoId && - photo_version == kDefaultPicasaPhotoVersion) || - (photo_id == kGooglePlusPhotoId && - photo_version == kDefaultGooglePlusPhotoVersion)); -} - -ProfileImageDownloader::ProfileImageDownloader(Delegate* delegate) - : delegate_(delegate) { -} - -void ProfileImageDownloader::Start() { - VLOG(1) << "Starting profile image downloader..."; - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - TokenService* service = - ProfileManager::GetDefaultProfile()->GetTokenService(); - if (!service) { - // This can happen in some test paths. - LOG(WARNING) << "User has no token service"; - if (delegate_) - delegate_->OnDownloadFailure(); - return; - } - if (service->HasTokenForService(GaiaConstants::kPicasaService)) { - auth_token_ = - service->GetTokenForService(GaiaConstants::kPicasaService); - StartFetchingImage(); - } else { - registrar_.Add(this, - chrome::NOTIFICATION_TOKEN_AVAILABLE, - content::Source(service)); - registrar_.Add(this, - chrome::NOTIFICATION_TOKEN_REQUEST_FAILED, - content::Source(service)); - } -} - -void ProfileImageDownloader::StartFetchingImage() { - std::string email = UserManager::Get()->logged_in_user().email(); - if (email.empty()) - return; - VLOG(1) << "Fetching user entry with token: " << auth_token_; - user_entry_fetcher_.reset(content::URLFetcher::Create( - GURL(kUserEntryURL), content::URLFetcher::GET, this)); - user_entry_fetcher_->SetRequestContext( - ProfileManager::GetDefaultProfile()->GetRequestContext()); - if (!auth_token_.empty()) { - user_entry_fetcher_->SetExtraRequestHeaders( - base::StringPrintf(kAuthorizationHeader, auth_token_.c_str())); - } - user_entry_fetcher_->Start(); -} - -ProfileImageDownloader::~ProfileImageDownloader() {} - -void ProfileImageDownloader::OnURLFetchComplete( - const content::URLFetcher* source) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - std::string data; - source->GetResponseAsString(&data); - if (source->GetResponseCode() != 200) { - LOG(ERROR) << "Response code is " << source->GetResponseCode(); - LOG(ERROR) << "Url is " << source->GetURL().spec(); - LOG(ERROR) << "Data is " << data; - if (delegate_) - delegate_->OnDownloadFailure(); - return; - } - - if (source == user_entry_fetcher_.get()) { - std::string image_url = GetProfileImageURL(data); - if (image_url.empty()) { - if (delegate_) - delegate_->OnDownloadFailure(); - return; - } - if (IsDefaultProfileImageURL(image_url)) { - if (delegate_) - delegate_->OnDownloadDefaultImage(); - return; - } - VLOG(1) << "Fetching profile image from " << image_url; - profile_image_fetcher_.reset(content::URLFetcher::Create( - GURL(image_url), content::URLFetcher::GET, this)); - profile_image_fetcher_->SetRequestContext( - ProfileManager::GetDefaultProfile()->GetRequestContext()); - if (!auth_token_.empty()) { - profile_image_fetcher_->SetExtraRequestHeaders( - base::StringPrintf(kAuthorizationHeader, auth_token_.c_str())); - } - profile_image_fetcher_->Start(); - } else if (source == profile_image_fetcher_.get()) { - VLOG(1) << "Decoding the image..."; - scoped_refptr image_decoder = new ImageDecoder( - this, data); - image_decoder->Start(); - } -} - -void ProfileImageDownloader::OnImageDecoded(const ImageDecoder* decoder, - const SkBitmap& decoded_image) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SkBitmap resized_image = skia::ImageOperations::Resize( - decoded_image, - skia::ImageOperations::RESIZE_BEST, - login::kUserImageSize, - login::kUserImageSize); - if (delegate_) - delegate_->OnDownloadSuccess(resized_image); -} - -void ProfileImageDownloader::OnDecodeImageFailed(const ImageDecoder* decoder) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (delegate_) - delegate_->OnDownloadFailure(); -} - -void ProfileImageDownloader::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK(type == chrome::NOTIFICATION_TOKEN_AVAILABLE || - type == chrome::NOTIFICATION_TOKEN_REQUEST_FAILED); - - TokenService::TokenAvailableDetails* token_details = - content::Details(details).ptr(); - if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) { - if (token_details->service() == GaiaConstants::kPicasaService) { - registrar_.RemoveAll(); - auth_token_ = token_details->token(); - StartFetchingImage(); - } - } else { - if (token_details->service() == GaiaConstants::kPicasaService) { - LOG(WARNING) << "ProfileImageDownloader: token request failed"; - if (delegate_) - delegate_->OnDownloadFailure(); - } - } -} - -} // namespace chromeos diff --git a/chrome/browser/chromeos/login/profile_image_downloader.h b/chrome/browser/chromeos/login/profile_image_downloader.h deleted file mode 100644 index 8701b34..0000000 --- a/chrome/browser/chromeos/login/profile_image_downloader.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_PROFILE_IMAGE_DOWNLOADER_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_PROFILE_IMAGE_DOWNLOADER_H_ -#pragma once - -#include - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/chromeos/login/image_decoder.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/common/url_fetcher_delegate.h" -#include "googleurl/src/gurl.h" - -namespace chromeos { - -// Downloads user profile image, decodes it in a sandboxed process. -class ProfileImageDownloader : public content::URLFetcherDelegate, - public ImageDecoder::Delegate, - public content::NotificationObserver { - public: - // Enum for reporting histograms about profile picture download. - enum DownloadResult { - kDownloadSuccessChanged, - kDownloadSuccess, - kDownloadFailure, - kDownloadDefault, - - // Must be the last, convenient count. - kDownloadResultsCount - }; - - // Reports on success or failure of Profile image download. It is OK to - // delete the |ProfileImageDownloader| instance in any of these handlers. - class Delegate { - public: - virtual ~Delegate() {} - - // Called when image is successfully downloaded and decoded. - virtual void OnDownloadSuccess(const SkBitmap& image) = 0; - - // Called on download failure. - virtual void OnDownloadFailure() {} - - // Called when user has the default profile image and we won't download - // it. - virtual void OnDownloadDefaultImage() {} - }; - - explicit ProfileImageDownloader(Delegate* delegate); - virtual ~ProfileImageDownloader(); - - // Starts downloading the picture if the necessary authorization token is - // ready. If not, subscribes to token service and starts fetching if the - // token is available. Should not be called more than once. - void Start(); - - private: - // Overriden from content::URLFetcherDelegate: - virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE; - - // Overriden from ImageDecoder::Delegate: - virtual void OnImageDecoded(const ImageDecoder* decoder, - const SkBitmap& decoded_image) OVERRIDE; - virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE; - - // Overriden from content::NotificationObserver: - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - - // Searches for profile image URL in user entry response from Picasa. - // Returns an empty string on failure. - std::string GetProfileImageURL(const std::string& data) const; - - // Returns true if the image url is url of the default profile picture. - bool IsDefaultProfileImageURL(const std::string& url) const; - - // Issues the first request to get user profile image. - void StartFetchingImage(); - - Delegate* delegate_; - std::string auth_token_; - scoped_ptr user_entry_fetcher_; - scoped_ptr profile_image_fetcher_; - content::NotificationRegistrar registrar_; - - DISALLOW_COPY_AND_ASSIGN(ProfileImageDownloader); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_PROFILE_IMAGE_DOWNLOADER_H_ diff --git a/chrome/browser/chromeos/login/user_image_loader.cc b/chrome/browser/chromeos/login/user_image_loader.cc index 2d635dd..21b8813 100644 --- a/chrome/browser/chromeos/login/user_image_loader.cc +++ b/chrome/browser/chromeos/login/user_image_loader.cc @@ -9,7 +9,6 @@ #include "base/file_util.h" #include "base/message_loop.h" #include "chrome/browser/chromeos/login/helper.h" -#include "chrome/browser/chromeos/login/image_decoder.h" #include "content/public/browser/browser_thread.h" #include "skia/ext/image_operations.h" #include "third_party/skia/include/core/SkBitmap.h" diff --git a/chrome/browser/chromeos/login/user_image_loader.h b/chrome/browser/chromeos/login/user_image_loader.h index e507d10..a3212ac5 100644 --- a/chrome/browser/chromeos/login/user_image_loader.h +++ b/chrome/browser/chromeos/login/user_image_loader.h @@ -11,7 +11,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" -#include "chrome/browser/chromeos/login/image_decoder.h" +#include "chrome/browser/image_decoder.h" class MessageLoop; class SkBitmap; diff --git a/chrome/browser/chromeos/login/user_manager.cc b/chrome/browser/chromeos/login/user_manager.cc index 6b90367..b64c68b6 100644 --- a/chrome/browser/chromeos/login/user_manager.cc +++ b/chrome/browser/chromeos/login/user_manager.cc @@ -36,6 +36,8 @@ #include "chrome/browser/defaults.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/scoped_user_pref_update.h" +#include "chrome/browser/profiles/profile_downloader.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/web_ui_util.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_paths.h" @@ -85,6 +87,17 @@ const long kProfileImageDownloadDelayMs = 10000; base::LazyInstance g_user_manager = LAZY_INSTANCE_INITIALIZER; +// Enum for reporting histograms about profile picture download. +enum ProfileDownloadResult { + kDownloadSuccessChanged, + kDownloadSuccess, + kDownloadFailure, + kDownloadDefault, + + // Must be the last, convenient count. + kDownloadResultsCount +}; + // Used to handle the asynchronous response of deleting a cryptohome directory. class RemoveAttempt : public CryptohomeLibrary::Delegate { public: @@ -454,7 +467,13 @@ void UserManager::DownloadProfileImage() { // Another download is already in progress return; } - profile_image_downloader_.reset(new ProfileImageDownloader(this)); + + if (logged_in_user().email().empty()) { + // This is a guest login so there's no profile image to download. + return; + } + + profile_image_downloader_.reset(new ProfileDownloader(this)); profile_image_downloader_->Start(); profile_image_load_start_time_ = base::Time::Now(); } @@ -789,65 +808,65 @@ void UserManager::CheckOwnership() { is_owner)); } -void UserManager::OnDownloadSuccess(const SkBitmap& image) { - VLOG(1) << "Downloaded profile image for logged-in user."; - UMA_HISTOGRAM_ENUMERATION("UserImageDownloadResult.LoggedIn", - ProfileImageDownloader::kDownloadSuccess, - ProfileImageDownloader::kDownloadResultsCount); +int UserManager::GetDesiredImageSideLength() { + return login::kUserImageSize; +} - // Check if this image is not the same as already downloaded. - std::string new_image_data_url = web_ui_util::GetImageDataUrl(image); - if (!downloaded_profile_image_data_url_.empty() && - new_image_data_url == downloaded_profile_image_data_url_) - return; +Profile* UserManager::GetBrowserProfile() { + return ProfileManager::GetDefaultProfile(); +} - downloaded_profile_image_data_url_ = new_image_data_url; - downloaded_profile_image_ = image; +void UserManager::OnDownloadComplete(ProfileDownloader* downloader, + bool success) { + ProfileDownloadResult result; + if (!success) + result = kDownloadFailure; + else if (downloader->GetProfilePicture().isNull()) + result = kDownloadDefault; + else + result = kDownloadSuccess; + UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult", + result, kDownloadResultsCount); - if (logged_in_user().image_index() == User::kProfileImageIndex) { - std::string current_image_data_url = - web_ui_util::GetImageDataUrl(logged_in_user().image()); - if (current_image_data_url == new_image_data_url) + if (result == kDownloadSuccess) { + // Check if this image is not the same as already downloaded. + std::string new_image_data_url = + web_ui_util::GetImageDataUrl(downloader->GetProfilePicture()); + if (!downloaded_profile_image_data_url_.empty() && + new_image_data_url == downloaded_profile_image_data_url_) return; - VLOG(1) << "Updating profile image for logged-in user"; - UMA_HISTOGRAM_ENUMERATION("UserImageDownloadResult.LoggedIn", - ProfileImageDownloader::kDownloadSuccessChanged, - ProfileImageDownloader::kDownloadResultsCount); + downloaded_profile_image_data_url_ = new_image_data_url; + downloaded_profile_image_ = downloader->GetProfilePicture(); - // This will persist |downloaded_profile_image_| to file. - SaveUserImageFromProfileImage(logged_in_user().email()); - } + if (logged_in_user().image_index() == User::kProfileImageIndex) { + std::string current_image_data_url = + web_ui_util::GetImageDataUrl(logged_in_user().image()); + if (current_image_data_url == new_image_data_url) + return; - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED, - content::Source(this), - content::Details(&image)); + VLOG(1) << "Updating profile image for logged-in user"; + UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult", + kDownloadSuccessChanged, + kDownloadResultsCount); - profile_image_downloader_.reset(); -} + // This will persist |downloaded_profile_image_| to file. + SaveUserImageFromProfileImage(logged_in_user().email()); + } + } -void UserManager::OnDownloadFailure() { - VLOG(1) << "Download of profile image for logged-in user failed."; - UMA_HISTOGRAM_ENUMERATION("UserImageDownloadResult.LoggedIn", - ProfileImageDownloader::kDownloadFailure, - ProfileImageDownloader::kDownloadResultsCount); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, - content::Source(this), - content::NotificationService::NoDetails()); - profile_image_downloader_.reset(); -} + if (result == kDownloadSuccess) { + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED, + content::Source(this), + content::Details(&downloader->GetProfilePicture())); + } else { + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, + content::Source(this), + content::NotificationService::NoDetails()); + } -void UserManager::OnDownloadDefaultImage() { - VLOG(1) << "Logged-in user still has the default profile image."; - UMA_HISTOGRAM_ENUMERATION("UserImageDownloadResult.LoggedIn", - ProfileImageDownloader::kDownloadDefault, - ProfileImageDownloader::kDownloadResultsCount); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, - content::Source(this), - content::NotificationService::NoDetails()); profile_image_downloader_.reset(); } diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h index 4e3aa2f..d1137a9 100644 --- a/chrome/browser/chromeos/login/user_manager.h +++ b/chrome/browser/chromeos/login/user_manager.h @@ -14,15 +14,16 @@ #include "base/observer_list.h" #include "base/synchronization/lock.h" #include "base/time.h" -#include "chrome/browser/chromeos/login/profile_image_downloader.h" #include "chrome/browser/chromeos/login/user.h" #include "chrome/browser/chromeos/login/user_image_loader.h" +#include "chrome/browser/profiles/profile_downloader_delegate.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "third_party/skia/include/core/SkBitmap.h" class FilePath; class PrefService; +class ProfileDownloader; namespace base { template struct DefaultLazyInstanceTraits; @@ -34,7 +35,7 @@ class RemoveUserDelegate; // This class provides a mechanism for discovering users who have logged // into this chromium os device before and updating that list. -class UserManager : public ProfileImageDownloader::Delegate, +class UserManager : public ProfileDownloaderDelegate, public content::NotificationObserver { public: // Returns a shared instance of a UserManager. Not thread-safe, should only be @@ -210,10 +211,11 @@ class UserManager : public ProfileImageDownloader::Delegate, // Checks current user's ownership on file thread. void CheckOwnership(); - // ProfileImageDownloader::Delegate implementation. - virtual void OnDownloadSuccess(const SkBitmap& image) OVERRIDE; - virtual void OnDownloadFailure() OVERRIDE; - virtual void OnDownloadDefaultImage() OVERRIDE; + // ProfileDownloaderDelegate implementation. + virtual int GetDesiredImageSideLength() OVERRIDE; + virtual Profile* GetBrowserProfile() OVERRIDE; + virtual void OnDownloadComplete(ProfileDownloader* downloader, + bool success) OVERRIDE; // Creates a new User instance. User* CreateUser(const std::string& email) const; @@ -259,7 +261,7 @@ class UserManager : public ProfileImageDownloader::Delegate, ObserverList observer_list_; // Download user profile image on login to update it if it's changed. - scoped_ptr profile_image_downloader_; + scoped_ptr profile_image_downloader_; // Time when the profile image download has started. base::Time profile_image_load_start_time_; diff --git a/chrome/browser/image_decoder.cc b/chrome/browser/image_decoder.cc new file mode 100644 index 0000000..3fb7aa8 --- /dev/null +++ b/chrome/browser/image_decoder.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2011 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/image_decoder.h" + +#include "base/bind.h" +#include "chrome/browser/browser_process.h" +#include "chrome/common/chrome_utility_messages.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +ImageDecoder::ImageDecoder(Delegate* delegate, + const std::string& image_data) + : delegate_(delegate), + image_data_(image_data.begin(), image_data.end()), + target_thread_id_(BrowserThread::UI) { +} + +ImageDecoder::~ImageDecoder() {} + +void ImageDecoder::Start() { + if (!BrowserThread::GetCurrentThreadIdentifier(&target_thread_id_)) { + NOTREACHED(); + return; + } + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&ImageDecoder::DecodeImageInSandbox, this, image_data_)); +} + +bool ImageDecoder::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ImageDecoder, message) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded, + OnDecodeImageSucceeded) + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed, + OnDecodeImageFailed) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void ImageDecoder::OnDecodeImageSucceeded(const SkBitmap& decoded_image) { + DCHECK(BrowserThread::CurrentlyOn(target_thread_id_)); + if (delegate_) + delegate_->OnImageDecoded(this, decoded_image); +} + +void ImageDecoder::OnDecodeImageFailed() { + DCHECK(BrowserThread::CurrentlyOn(target_thread_id_)); + if (delegate_) + delegate_->OnDecodeImageFailed(this); +} + +void ImageDecoder::DecodeImageInSandbox( + const std::vector& image_data) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + UtilityProcessHost* utility_process_host = + new UtilityProcessHost(this, + target_thread_id_); + utility_process_host->Send(new ChromeUtilityMsg_DecodeImage(image_data)); +} diff --git a/chrome/browser/image_decoder.h b/chrome/browser/image_decoder.h new file mode 100644 index 0000000..ec90d01 --- /dev/null +++ b/chrome/browser/image_decoder.h @@ -0,0 +1,62 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_IMAGE_DECODER_H_ +#define CHROME_BROWSER_IMAGE_DECODER_H_ +#pragma once + +#include +#include + +#include "content/browser/utility_process_host.h" + +class SkBitmap; + +// Decodes an image in a sandboxed process. +class ImageDecoder : public UtilityProcessHost::Client { + public: + class Delegate { + public: + // Called when image is decoded. + // |decoder| is used to identify the image in case of decoding several + // images simultaneously. + virtual void OnImageDecoded(const ImageDecoder* decoder, + const SkBitmap& decoded_image) = 0; + + // Called when decoding image failed. Delegate can do some cleanup in + // this handler. + virtual void OnDecodeImageFailed(const ImageDecoder* decoder) {} + + protected: + virtual ~Delegate() {} + }; + + ImageDecoder(Delegate* delegate, + const std::string& image_data); + + // Starts image decoding. + void Start(); + + private: + // It's a reference counted object, so destructor is private. + virtual ~ImageDecoder(); + + // Overidden from UtilityProcessHost::Client: + virtual bool OnMessageReceived(const IPC::Message& message); + + // IPC message handlers. + void OnDecodeImageSucceeded(const SkBitmap& decoded_image); + void OnDecodeImageFailed(); + + // Launches sandboxed process that will decode the image. + void DecodeImageInSandbox(const std::vector& image_data); + + Delegate* delegate_; + std::vector image_data_; + content::BrowserThread::ID target_thread_id_; + + DISALLOW_COPY_AND_ASSIGN(ImageDecoder); +}; + +#endif // CHROME_BROWSER_IMAGE_DECODER_H_ diff --git a/chrome/browser/profiles/profile_downloader.cc b/chrome/browser/profiles/profile_downloader.cc new file mode 100644 index 0000000..468cc8c --- /dev/null +++ b/chrome/browser/profiles/profile_downloader.cc @@ -0,0 +1,305 @@ +// Copyright (c) 2011 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/profiles/profile_downloader.h" + +#include +#include + +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/string_split.h" +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "chrome/browser/net/gaia/token_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_downloader_delegate.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/net/gaia/gaia_constants.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" +#include "content/public/common/url_fetcher.h" +#include "googleurl/src/gurl.h" +#include "skia/ext/image_operations.h" + +using content::BrowserThread; + +namespace { + +// Template for optional authorization header. +const char kAuthorizationHeader[] = "Authorization: GoogleLogin auth=%s"; + +// URL requesting Picasa API for user info. +const char kUserEntryURL[] = + "http://picasaweb.google.com/data/entry/api/user/default?alt=json"; +// Path in JSON dictionary to user's photo thumbnail URL. +const char kPhotoThumbnailURLPath[] = "entry.gphoto$thumbnail.$t"; + +const char kNickNamePath[] = "entry.gphoto$nickname.$t"; + +// Path format for specifying thumbnail's size. +const char kThumbnailSizeFormat[] = "s%d-c"; +// Default Picasa thumbnail size. +const int kDefaultThumbnailSize = 64; + +// Separator of URL path components. +const char kURLPathSeparator = '/'; + +// Photo ID of the Picasa Web Albums profile picture (base64 of 0). +const char kPicasaPhotoId[] = "AAAAAAAAAAA"; + +// Photo version of the default PWA profile picture (base64 of 1). +const char kDefaultPicasaPhotoVersion[] = "AAAAAAAAAAE"; + +// Photo ID of the Google+ profile picture (base64 of 2). +const char kGooglePlusPhotoId[] = "AAAAAAAAAAI"; + +// Photo version of the default Google+ profile picture (base64 of 0). +const char kDefaultGooglePlusPhotoVersion[] = "AAAAAAAAAAA"; + +// Number of path components in profile picture URL. +const size_t kProfileImageURLPathComponentsCount = 7; + +// Index of path component with photo ID. +const int kPhotoIdPathComponentIndex = 2; + +// Index of path component with photo version. +const int kPhotoVersionPathComponentIndex = 3; + +} // namespace + +bool ProfileDownloader::GetProfileNickNameAndImageURL(const std::string& data, + string16* nick_name, + std::string* url) const { + DCHECK(nick_name); + DCHECK(url); + *nick_name = string16(); + *url = std::string(); + + int error_code = -1; + std::string error_message; + scoped_ptr root_value(base::JSONReader::ReadAndReturnError( + data, false, &error_code, &error_message)); + if (!root_value.get()) { + LOG(ERROR) << "Error while parsing Picasa user entry response: " + << error_message; + return false; + } + if (!root_value->IsType(base::Value::TYPE_DICTIONARY)) { + LOG(ERROR) << "JSON root is not a dictionary: " + << root_value->GetType(); + return false; + } + base::DictionaryValue* root_dictionary = + static_cast(root_value.get()); + + if (!root_dictionary->GetString(kNickNamePath, nick_name)) { + LOG(ERROR) << "Can't find nick name path in JSON data: " + << data; + return false; + } + + std::string thumbnail_url_string; + if (!root_dictionary->GetString( + kPhotoThumbnailURLPath, &thumbnail_url_string)) { + LOG(ERROR) << "Can't find thumbnail path in JSON data: " + << data; + return false; + } + + // Try to change the size of thumbnail we are going to get. + // Typical URL looks like this: + // http://lh0.ggpht.com/-abcd1aBCDEf/AAAA/AAA_A/abc12/s64-c/1234567890.jpg + std::string default_thumbnail_size_path_component( + base::StringPrintf(kThumbnailSizeFormat, kDefaultThumbnailSize)); + int image_size = delegate_->GetDesiredImageSideLength(); + std::string new_thumbnail_size_path_component( + base::StringPrintf(kThumbnailSizeFormat, image_size)); + size_t thumbnail_size_pos = + thumbnail_url_string.find(default_thumbnail_size_path_component); + if (thumbnail_size_pos != std::string::npos) { + size_t thumbnail_size_end = + thumbnail_size_pos + default_thumbnail_size_path_component.size(); + thumbnail_url_string = + thumbnail_url_string.substr(0, thumbnail_size_pos) + + new_thumbnail_size_path_component + + thumbnail_url_string.substr( + thumbnail_size_end, + thumbnail_url_string.size() - thumbnail_size_end); + } else { + LOG(WARNING) << "Hasn't found thumbnail size part in image URL: " + << thumbnail_url_string; + // Use the thumbnail URL we have. + } + + GURL thumbnail_url(thumbnail_url_string); + if (!thumbnail_url.is_valid()) { + LOG(ERROR) << "Thumbnail URL is not valid: " << thumbnail_url_string; + return false; + } + *url = thumbnail_url.spec(); + return true; +} + +bool ProfileDownloader::IsDefaultProfileImageURL(const std::string& url) const { + GURL image_url_object(url); + DCHECK(image_url_object.is_valid()); + VLOG(1) << "URL to check for default image: " << image_url_object.spec(); + std::vector path_components; + base::SplitString(image_url_object.path(), + kURLPathSeparator, + &path_components); + + if (path_components.size() != kProfileImageURLPathComponentsCount) + return false; + + const std::string& photo_id = path_components[kPhotoIdPathComponentIndex]; + const std::string& photo_version = + path_components[kPhotoVersionPathComponentIndex]; + + // There are at least two pairs of (ID, version) for the default photo: + // the default Google+ profile photo and the default Picasa profile photo. + return ((photo_id == kPicasaPhotoId && + photo_version == kDefaultPicasaPhotoVersion) || + (photo_id == kGooglePlusPhotoId && + photo_version == kDefaultGooglePlusPhotoVersion)); +} + +ProfileDownloader::ProfileDownloader(ProfileDownloaderDelegate* delegate) + : delegate_(delegate) { + DCHECK(delegate_); +} + +void ProfileDownloader::Start() { + VLOG(1) << "Starting profile downloader..."; + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + TokenService* service = delegate_->GetBrowserProfile()->GetTokenService(); + if (!service) { + // This can happen in some test paths. + LOG(WARNING) << "User has no token service"; + delegate_->OnDownloadComplete(this, false); + return; + } + if (service->HasTokenForService(GaiaConstants::kPicasaService)) { + auth_token_ = + service->GetTokenForService(GaiaConstants::kPicasaService); + StartFetchingImage(); + } else { + registrar_.Add(this, + chrome::NOTIFICATION_TOKEN_AVAILABLE, + content::Source(service)); + registrar_.Add(this, + chrome::NOTIFICATION_TOKEN_REQUEST_FAILED, + content::Source(service)); + } +} + +const string16& ProfileDownloader::GetProfileFullName() const { + return profile_full_name_; +} + +const SkBitmap& ProfileDownloader::GetProfilePicture() const { + return profile_picture_; +} + +void ProfileDownloader::StartFetchingImage() { + VLOG(1) << "Fetching user entry with token: " << auth_token_; + user_entry_fetcher_.reset(content::URLFetcher::Create( + GURL(kUserEntryURL), content::URLFetcher::GET, this)); + user_entry_fetcher_->SetRequestContext( + delegate_->GetBrowserProfile()->GetRequestContext()); + if (!auth_token_.empty()) { + user_entry_fetcher_->SetExtraRequestHeaders( + base::StringPrintf(kAuthorizationHeader, auth_token_.c_str())); + } + user_entry_fetcher_->Start(); +} + +ProfileDownloader::~ProfileDownloader() {} + +void ProfileDownloader::OnURLFetchComplete(const content::URLFetcher* source) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + std::string data; + source->GetResponseAsString(&data); + if (source->GetResponseCode() != 200) { + LOG(ERROR) << "Response code is " << source->GetResponseCode(); + LOG(ERROR) << "Url is " << source->GetURL().spec(); + LOG(ERROR) << "Data is " << data; + delegate_->OnDownloadComplete(this, false); + return; + } + + if (source == user_entry_fetcher_.get()) { + std::string image_url; + if (!GetProfileNickNameAndImageURL(data, &profile_full_name_, &image_url)) { + delegate_->OnDownloadComplete(this, false); + return; + } + if (IsDefaultProfileImageURL(image_url)) { + delegate_->OnDownloadComplete(this, true); + return; + } + VLOG(1) << "Fetching profile image from " << image_url; + profile_image_fetcher_.reset(content::URLFetcher::Create( + GURL(image_url), content::URLFetcher::GET, this)); + profile_image_fetcher_->SetRequestContext( + delegate_->GetBrowserProfile()->GetRequestContext()); + if (!auth_token_.empty()) { + profile_image_fetcher_->SetExtraRequestHeaders( + base::StringPrintf(kAuthorizationHeader, auth_token_.c_str())); + } + profile_image_fetcher_->Start(); + } else if (source == profile_image_fetcher_.get()) { + VLOG(1) << "Decoding the image..."; + scoped_refptr image_decoder = new ImageDecoder( + this, data); + image_decoder->Start(); + } +} + +void ProfileDownloader::OnImageDecoded(const ImageDecoder* decoder, + const SkBitmap& decoded_image) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + int image_size = delegate_->GetDesiredImageSideLength(); + profile_picture_ = skia::ImageOperations::Resize( + decoded_image, + skia::ImageOperations::RESIZE_BEST, + image_size, + image_size); + delegate_->OnDownloadComplete(this, true); +} + +void ProfileDownloader::OnDecodeImageFailed(const ImageDecoder* decoder) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + delegate_->OnDownloadComplete(this, false); +} + +void ProfileDownloader::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK(type == chrome::NOTIFICATION_TOKEN_AVAILABLE || + type == chrome::NOTIFICATION_TOKEN_REQUEST_FAILED); + + TokenService::TokenAvailableDetails* token_details = + content::Details(details).ptr(); + if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) { + if (token_details->service() == GaiaConstants::kPicasaService) { + registrar_.RemoveAll(); + auth_token_ = token_details->token(); + StartFetchingImage(); + } + } else { + if (token_details->service() == GaiaConstants::kPicasaService) { + LOG(WARNING) << "ProfileDownloader: token request failed"; + delegate_->OnDownloadComplete(this, false); + } + } +} diff --git a/chrome/browser/profiles/profile_downloader.h b/chrome/browser/profiles/profile_downloader.h new file mode 100644 index 0000000..2b9733e --- /dev/null +++ b/chrome/browser/profiles/profile_downloader.h @@ -0,0 +1,83 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_PROFILES_PROFILE_DOWNLOADER_H_ +#define CHROME_BROWSER_PROFILES_PROFILE_DOWNLOADER_H_ +#pragma once + +#include + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/string16.h" +#include "chrome/browser/image_decoder.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/common/url_fetcher_delegate.h" +#include "googleurl/src/gurl.h" +#include "third_party/skia/include/core/SkBitmap.h" + +class ProfileDownloaderDelegate; + +// Downloads user profile information. The profile picture is decoded in a +// sandboxed process. +class ProfileDownloader : public content::URLFetcherDelegate, + public ImageDecoder::Delegate, + public content::NotificationObserver { + public: + explicit ProfileDownloader(ProfileDownloaderDelegate* delegate); + virtual ~ProfileDownloader(); + + // Starts downloading profile information if the necessary authorization token + // is ready. If not, subscribes to token service and starts fetching if the + // token is available. Should not be called more than once. + void Start(); + + // On successful download this returns the full name of the user. For example + // "Pat Smith". + const string16& GetProfileFullName() const; + + // On successful download this returns the profile picture of the user. + // For users with no profile picture set (that is, they have the default + // profile picture) this will return an Null bitmap. + const SkBitmap& GetProfilePicture() const; + + private: + // Overriden from content::URLFetcherDelegate: + virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE; + + // Overriden from ImageDecoder::Delegate: + virtual void OnImageDecoded(const ImageDecoder* decoder, + const SkBitmap& decoded_image) OVERRIDE; + virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE; + + // Overriden from content::NotificationObserver: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Parses the entry response from Picasa and gets the nick name and + // and profile image URL. Returns false to indicate a parsing error. + bool GetProfileNickNameAndImageURL(const std::string& data, + string16* nick_name, + std::string* url) const; + + // Returns true if the image url is url of the default profile picture. + bool IsDefaultProfileImageURL(const std::string& url) const; + + // Issues the first request to get user profile image. + void StartFetchingImage(); + + ProfileDownloaderDelegate* delegate_; + std::string auth_token_; + scoped_ptr user_entry_fetcher_; + scoped_ptr profile_image_fetcher_; + content::NotificationRegistrar registrar_; + string16 profile_full_name_; + SkBitmap profile_picture_; + + DISALLOW_COPY_AND_ASSIGN(ProfileDownloader); +}; + +#endif // CHROME_BROWSER_PROFILES_PROFILE_DOWNLOADER_H_ diff --git a/chrome/browser/profiles/profile_downloader_delegate.h b/chrome/browser/profiles/profile_downloader_delegate.h new file mode 100644 index 0000000..2a71a19 --- /dev/null +++ b/chrome/browser/profiles/profile_downloader_delegate.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_PROFILES_PROFILE_DOWNLOADER_DELEGATE_H_ +#define CHROME_BROWSER_PROFILES_PROFILE_DOWNLOADER_DELEGATE_H_ +#pragma once + +#include + +#include "base/basictypes.h" +#include "base/string16.h" + +class Profile; +class ProfileDownloader; + +// Reports on success or failure of Profile download. It is OK to delete the +// |ProfileImageDownloader| instance in any of these handlers. +class ProfileDownloaderDelegate { + public: + virtual ~ProfileDownloaderDelegate() {} + + // Returns the desired side length of the profile image. If 0, returns image + // of the originally uploaded size. + virtual int GetDesiredImageSideLength() = 0; + + // Returns the browser profile associated with this download request. + virtual Profile* GetBrowserProfile() = 0; + + // Called when the download is complete. On success delegate should query + // the downloader for values. + virtual void OnDownloadComplete(ProfileDownloader* downloader, + bool success) = 0; +}; + +#endif // CHROME_BROWSER_PROFILES_PROFILE_DOWNLOADER_DELEGATE_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 5e1c77a..ba4b788 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -570,8 +570,6 @@ 'browser/chromeos/login/helper.h', 'browser/chromeos/login/html_page_screen.cc', 'browser/chromeos/login/html_page_screen.h', - 'browser/chromeos/login/image_decoder.cc', - 'browser/chromeos/login/image_decoder.h', 'browser/chromeos/login/image_downloader.cc', 'browser/chromeos/login/image_downloader.h', 'browser/chromeos/login/issue_response_handler.cc', @@ -613,8 +611,6 @@ 'browser/chromeos/login/parallel_authenticator.h', 'browser/chromeos/login/password_changed_view.cc', 'browser/chromeos/login/password_changed_view.h', - 'browser/chromeos/login/profile_image_downloader.cc', - 'browser/chromeos/login/profile_image_downloader.h', 'browser/chromeos/login/proxy_settings_dialog.cc', 'browser/chromeos/login/proxy_settings_dialog.h', 'browser/chromeos/login/registration_screen.cc', @@ -1394,6 +1390,8 @@ 'browser/idle_query_linux.cc', 'browser/idle_query_linux.h', 'browser/idle_win.cc', + 'browser/image_decoder.cc', + 'browser/image_decoder.h', 'browser/importer/external_process_importer_bridge.cc', 'browser/importer/external_process_importer_bridge.h', 'browser/importer/external_process_importer_client.cc', @@ -1952,6 +1950,9 @@ 'browser/profiles/profile.h', 'browser/profiles/profile_dependency_manager.cc', 'browser/profiles/profile_dependency_manager.h', + 'browser/profiles/profile_downloader.cc', + 'browser/profiles/profile_downloader.h', + 'browser/profiles/profile_downloader_delegate.h', 'browser/profiles/profile_impl.cc', 'browser/profiles/profile_impl.h', 'browser/profiles/profile_impl_io_data.cc', -- cgit v1.1