Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3765)

Unified Diff: chrome/browser/gaia_userinfo/profile_image_downloader.cc

Issue 8511064: GAIA Profile info prototype (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/gaia_userinfo/profile_image_downloader.cc
diff --git a/chrome/browser/gaia_userinfo/profile_image_downloader.cc b/chrome/browser/gaia_userinfo/profile_image_downloader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ad2343636d4b8864faca7ffdd08c1a64a55eac79
--- /dev/null
+++ b/chrome/browser/gaia_userinfo/profile_image_downloader.cc
@@ -0,0 +1,317 @@
+// 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/gaia_userinfo/profile_image_downloader.h"
+
+#include <string>
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.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/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"
+#include "third_party/skia/include/core/SkBitmap.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 kFullNamePath[] = "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
+
+std::string ProfileImageDownloader::GetProfileImageURL(
+ const std::string& data) {
+ int error_code = -1;
+ std::string error_message;
+ scoped_ptr<base::Value> 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<base::DictionaryValue*>(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();
+ }
+
+ if (!root_dictionary->GetString(kFullNamePath, &full_name_)) {
+ } else {
+ }
+
+ fprintf(stderr, "%s - got name: %s\n",
+ __func__, UTF16ToUTF8(full_name_).c_str());
+
+ // 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,
+ delegate_->GetDesiredImageSize()));
+ 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.
+ }
+
+ fprintf(stderr, "%s - thumbnail URL is : %s\n",
+ __func__, thumbnail_url_string.c_str());
+
+ 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<std::string> 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) {
+ DCHECK(delegate_);
+}
+
+void ProfileImageDownloader::Start() {
+ VLOG(1) << "Starting profile image downloader...";
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ TokenService* service =
+ delegate_->GetProfile()->GetTokenService();
+ if (!service) {
+ // This can happen in some test paths.
+ fprintf(stderr, "%s no token service\n", __func__);
+ LOG(WARNING) << "User has no token service";
+ delegate_->OnDownloadFailure();
+ return;
+ }
+ if (service->HasTokenForService(GaiaConstants::kPicasaService)) {
+ auth_token_ =
+ service->GetTokenForService(GaiaConstants::kPicasaService);
+ StartFetchingImage();
+ } else {
+ fprintf(stderr, "%s does not have picasa token, waiting\n", __func__);
+ }
+
+ registrar_.Add(this,
+ chrome::NOTIFICATION_TOKEN_AVAILABLE,
+ content::Source<TokenService>(service));
+ registrar_.Add(this,
+ chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
+ content::Source<TokenService>(service));
+}
+
+void ProfileImageDownloader::StartFetchingImage() {
+ std::string email = delegate_->GetProfileUserName();
+ 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(
+ delegate_->GetProfile()->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) {
+ fprintf(stderr, "%s, URL fetch error\n", __func__);
+ LOG(ERROR) << "Response code is " << source->GetResponseCode();
+ LOG(ERROR) << "Url is " << source->GetURL().spec();
+ LOG(ERROR) << "Data is " << data;
+ delegate_->OnDownloadFailure();
+
+/*
+ if (source->GetResponseCode() == 403) {
+ TokenService* service =
+ delegate_->GetProfile()->GetTokenService();
+ service->ClearTokenForService(GaiaConstants::kPicasaService);
+ service->StartFetchingMissingTokens();
+ }
+*/
+
+ return;
+ }
+
+ if (source == user_entry_fetcher_.get()) {
+ std::string image_url = GetProfileImageURL(data);
+ if (image_url.empty()) {
+ delegate_->OnDownloadFailure();
+ return;
+ }
+ if (IsDefaultProfileImageURL(image_url)) {
+ 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(
+ delegate_->GetProfile()->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<ImageDecoder> 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,
+ delegate_->GetDesiredImageSize(),
+ delegate_->GetDesiredImageSize());
+ delegate_->OnDownloadSuccess(resized_image, full_name_);
+}
+
+void ProfileImageDownloader::OnDecodeImageFailed(const ImageDecoder* decoder) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ 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);
+
+ fprintf(stderr, "%s\n", __func__);
+
+ TokenService::TokenAvailableDetails* token_details =
+ content::Details<TokenService::TokenAvailableDetails>(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";
+ delegate_->OnDownloadFailure();
+ }
+ }
+}
« no previous file with comments | « chrome/browser/gaia_userinfo/profile_image_downloader.h ('k') | chrome/browser/profiles/avatar_menu_model.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698