Home | History | Annotate | Download | only in screens
      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/chromeos/login/screens/user_image_screen.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/metrics/histogram.h"
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
     11 #include "chrome/browser/chromeos/camera_detector.h"
     12 #include "chrome/browser/chromeos/login/default_user_images.h"
     13 #include "chrome/browser/chromeos/login/login_utils.h"
     14 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
     15 #include "chrome/browser/chromeos/login/user_image.h"
     16 #include "chrome/browser/chromeos/login/user_image_manager.h"
     17 #include "chrome/browser/chromeos/login/user_manager.h"
     18 #include "chrome/browser/chromeos/login/wizard_controller.h"
     19 #include "chrome/common/url_constants.h"
     20 #include "content/public/browser/browser_thread.h"
     21 #include "content/public/browser/notification_service.h"
     22 #include "grit/generated_resources.h"
     23 #include "grit/theme_resources.h"
     24 #include "third_party/skia/include/core/SkBitmap.h"
     25 #include "ui/base/l10n/l10n_util.h"
     26 #include "ui/base/resource/resource_bundle.h"
     27 #include "ui/gfx/image/image_skia.h"
     28 #include "ui/webui/web_ui_util.h"
     29 
     30 using content::BrowserThread;
     31 
     32 namespace chromeos {
     33 
     34 namespace {
     35 
     36 // Time histogram suffix for profile image download.
     37 const char kProfileDownloadReason[] = "OOBE";
     38 
     39 }  // namespace
     40 
     41 UserImageScreen::UserImageScreen(ScreenObserver* screen_observer,
     42                                  UserImageScreenActor* actor)
     43     : WizardScreen(screen_observer),
     44       actor_(actor),
     45       weak_factory_(this),
     46       accept_photo_after_decoding_(false),
     47       selected_image_(User::kInvalidImageIndex),
     48       profile_picture_enabled_(false),
     49       profile_picture_data_url_(content::kAboutBlankURL),
     50       profile_picture_absent_(false) {
     51   actor_->SetDelegate(this);
     52   SetProfilePictureEnabled(true);
     53 }
     54 
     55 UserImageScreen::~UserImageScreen() {
     56   if (actor_)
     57     actor_->SetDelegate(NULL);
     58   if (image_decoder_.get())
     59     image_decoder_->set_delegate(NULL);
     60 }
     61 
     62 void UserImageScreen::CheckCameraPresence() {
     63   CameraDetector::StartPresenceCheck(
     64       base::Bind(&UserImageScreen::OnCameraPresenceCheckDone,
     65                  weak_factory_.GetWeakPtr()));
     66 }
     67 
     68 void UserImageScreen::OnCameraPresenceCheckDone() {
     69   if (actor_) {
     70     actor_->SetCameraPresent(
     71         CameraDetector::camera_presence() == CameraDetector::kCameraPresent);
     72   }
     73 }
     74 
     75 void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
     76   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     77   user_photo_ = gfx::ImageSkia();
     78   if (image_decoder_.get())
     79     image_decoder_->set_delegate(NULL);
     80   image_decoder_ = new ImageDecoder(this, raw_data,
     81                                     ImageDecoder::DEFAULT_CODEC);
     82   scoped_refptr<base::MessageLoopProxy> task_runner =
     83       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
     84   image_decoder_->Start(task_runner);
     85 }
     86 
     87 void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder,
     88                                      const SkBitmap& decoded_image) {
     89   DCHECK_EQ(image_decoder_.get(), decoder);
     90   user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
     91   if (accept_photo_after_decoding_)
     92     OnImageAccepted();
     93 }
     94 
     95 void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) {
     96   NOTREACHED() << "Failed to decode PNG image from WebUI";
     97 }
     98 
     99 void UserImageScreen::OnImageSelected(const std::string& image_type,
    100                                       const std::string& image_url) {
    101   if (image_url.empty())
    102     return;
    103   int user_image_index = User::kInvalidImageIndex;
    104   if (image_type == "default" &&
    105       IsDefaultImageUrl(image_url, &user_image_index)) {
    106     selected_image_ = user_image_index;
    107   } else if (image_type == "camera") {
    108     selected_image_ = User::kExternalImageIndex;
    109   } else if (image_type == "profile") {
    110     selected_image_ = User::kProfileImageIndex;
    111   } else {
    112     NOTREACHED() << "Unexpected image type: " << image_type;
    113   }
    114 }
    115 
    116 void UserImageScreen::OnImageAccepted() {
    117   UserManager* user_manager = UserManager::Get();
    118   UserImageManager* image_manager = user_manager->GetUserImageManager();
    119   std::string user_id = GetUser()->email();
    120   int uma_index = 0;
    121   switch (selected_image_) {
    122     case User::kExternalImageIndex:
    123       // Photo decoding may not have been finished yet.
    124       if (user_photo_.isNull()) {
    125         accept_photo_after_decoding_ = true;
    126         return;
    127       }
    128       image_manager->
    129           SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_));
    130       uma_index = kHistogramImageFromCamera;
    131       break;
    132     case User::kProfileImageIndex:
    133       image_manager->SaveUserImageFromProfileImage(user_id);
    134       uma_index = kHistogramImageFromProfile;
    135       break;
    136     default:
    137       DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
    138       image_manager->SaveUserDefaultImageIndex(user_id, selected_image_);
    139       uma_index = GetDefaultImageHistogramValue(selected_image_);
    140       break;
    141   }
    142   UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
    143                             uma_index,
    144                             kHistogramImagesCount);
    145   get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
    146 }
    147 
    148 
    149 void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled) {
    150   if (profile_picture_enabled_ == profile_picture_enabled)
    151     return;
    152   profile_picture_enabled_ = profile_picture_enabled;
    153   if (profile_picture_enabled) {
    154     registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
    155         content::NotificationService::AllSources());
    156     registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
    157         content::NotificationService::AllSources());
    158   } else {
    159     registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
    160         content::NotificationService::AllSources());
    161     registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
    162         content::NotificationService::AllSources());
    163   }
    164   if (actor_)
    165     actor_->SetProfilePictureEnabled(profile_picture_enabled);
    166 }
    167 
    168 void UserImageScreen::SetUserID(const std::string& user_id) {
    169   DCHECK(!user_id.empty());
    170   user_id_ = user_id;
    171 }
    172 
    173 void UserImageScreen::PrepareToShow() {
    174   if (actor_)
    175     actor_->PrepareToShow();
    176 }
    177 
    178 const User* UserImageScreen::GetUser() {
    179   if (user_id_.empty())
    180     return UserManager::Get()->GetLoggedInUser();
    181   const User* user = UserManager::Get()->FindUser(user_id_);
    182   DCHECK(user);
    183   return user;
    184 }
    185 
    186 void UserImageScreen::Show() {
    187   if (!actor_)
    188     return;
    189 
    190   actor_->Show();
    191   actor_->SetProfilePictureEnabled(profile_picture_enabled_);
    192 
    193   selected_image_ = GetUser()->image_index();
    194   actor_->SelectImage(selected_image_);
    195 
    196   if (profile_picture_enabled_) {
    197     // Start fetching the profile image.
    198     UserManager::Get()->GetUserImageManager()->
    199         DownloadProfileImage(kProfileDownloadReason);
    200   }
    201 
    202   AccessibilityManager::Get()->MaybeSpeak(
    203       l10n_util::GetStringUTF8(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT));
    204 }
    205 
    206 void UserImageScreen::Hide() {
    207   if (actor_)
    208     actor_->Hide();
    209 }
    210 
    211 std::string UserImageScreen::GetName() const {
    212   return WizardController::kUserImageScreenName;
    213 }
    214 
    215 void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) {
    216   if (actor_ == actor)
    217     actor_ = NULL;
    218 }
    219 
    220 void UserImageScreen::Observe(int type,
    221                               const content::NotificationSource& source,
    222                               const content::NotificationDetails& details) {
    223   DCHECK(profile_picture_enabled_);
    224   switch (type) {
    225     case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: {
    226       // We've got a new profile image.
    227       profile_picture_data_url_ = webui::GetBitmapDataUrl(
    228           *content::Details<const gfx::ImageSkia>(details).ptr()->bitmap());
    229       if (actor_)
    230         actor_->SendProfileImage(profile_picture_data_url_);
    231       break;
    232     }
    233     case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: {
    234       // User has a default profile image or fetching profile image has failed.
    235       profile_picture_absent_ = true;
    236       if (actor_)
    237         actor_->OnProfileImageAbsent();
    238       break;
    239     }
    240     default:
    241       NOTREACHED();
    242   }
    243 }
    244 
    245 bool UserImageScreen::profile_picture_absent() {
    246   return profile_picture_absent_;
    247 }
    248 
    249 int UserImageScreen::selected_image() {
    250   return selected_image_;
    251 }
    252 
    253 std::string UserImageScreen::profile_picture_data_url() {
    254   return profile_picture_data_url_;
    255 }
    256 
    257 }  // namespace chromeos
    258