- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / screens / user_image_screen.cc
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 "base/timer/timer.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
12 #include "chrome/browser/chromeos/camera_detector.h"
13 #include "chrome/browser/chromeos/login/default_user_images.h"
14 #include "chrome/browser/chromeos/login/login_utils.h"
15 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
16 #include "chrome/browser/chromeos/login/user_image.h"
17 #include "chrome/browser/chromeos/login/user_image_manager.h"
18 #include "chrome/browser/chromeos/login/user_manager.h"
19 #include "chrome/browser/chromeos/login/wizard_controller.h"
20 #include "chrome/common/url_constants.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_service.h"
23 #include "grit/generated_resources.h"
24 #include "grit/theme_resources.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/base/webui/web_ui_util.h"
29 #include "ui/gfx/image/image_skia.h"
30
31 using content::BrowserThread;
32
33 namespace chromeos {
34
35 namespace {
36
37 // Time histogram suffix for profile image download.
38 const char kProfileDownloadReason[] = "OOBE";
39
40 // Maximum ammount of time to wait for the user image to sync.
41 // The screen is shown iff sync failed or time limit exceeded.
42 const int kSyncTimeoutSeconds = 10;
43
44 }  // namespace
45
46 UserImageScreen::UserImageScreen(ScreenObserver* screen_observer,
47                                  UserImageScreenActor* actor)
48     : WizardScreen(screen_observer),
49       actor_(actor),
50       weak_factory_(this),
51       accept_photo_after_decoding_(false),
52       selected_image_(User::kInvalidImageIndex),
53       profile_picture_enabled_(false),
54       profile_picture_data_url_(content::kAboutBlankURL),
55       profile_picture_absent_(false),
56       is_screen_ready_(false),
57       user_has_selected_image_(false) {
58   actor_->SetDelegate(this);
59   SetProfilePictureEnabled(true);
60   registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
61       content::NotificationService::AllSources());
62 }
63
64 UserImageScreen::~UserImageScreen() {
65   if (actor_)
66     actor_->SetDelegate(NULL);
67   if (image_decoder_.get())
68     image_decoder_->set_delegate(NULL);
69 }
70
71 void UserImageScreen::OnScreenReady() {
72   is_screen_ready_ = true;
73   if (!IsWaitingForSync())
74     HideCurtain();
75 }
76
77 void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79   user_photo_ = gfx::ImageSkia();
80   if (image_decoder_.get())
81     image_decoder_->set_delegate(NULL);
82   image_decoder_ = new ImageDecoder(this, raw_data,
83                                     ImageDecoder::DEFAULT_CODEC);
84   scoped_refptr<base::MessageLoopProxy> task_runner =
85       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
86   image_decoder_->Start(task_runner);
87 }
88
89 void UserImageScreen::CheckCameraPresence() {
90   CameraDetector::StartPresenceCheck(
91       base::Bind(&UserImageScreen::OnCameraPresenceCheckDone,
92                  weak_factory_.GetWeakPtr()));
93 }
94
95 void UserImageScreen::OnCameraPresenceCheckDone() {
96   if (actor_) {
97     actor_->SetCameraPresent(
98         CameraDetector::camera_presence() == CameraDetector::kCameraPresent);
99   }
100 }
101
102 void UserImageScreen::HideCurtain() {
103   if (actor_)
104     actor_->HideCurtain();
105   AccessibilityManager::Get()->MaybeSpeak(
106       l10n_util::GetStringUTF8(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT));
107 }
108
109
110 void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder,
111                                      const SkBitmap& decoded_image) {
112   DCHECK_EQ(image_decoder_.get(), decoder);
113   user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
114   if (accept_photo_after_decoding_)
115     OnImageAccepted();
116 }
117
118 void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) {
119   NOTREACHED() << "Failed to decode PNG image from WebUI";
120 }
121
122 void UserImageScreen::OnInitialSync(bool local_image_updated) {
123   DCHECK(sync_timer_.get());
124   sync_timer_->Stop();
125   sync_timer_.reset();
126   UserManager::Get()->GetUserImageManager()->GetSyncObserver()->
127       RemoveObserver(this);
128   if (!local_image_updated) {
129     if (is_screen_ready_)
130       HideCurtain();
131     return;
132   }
133   get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
134 }
135
136 void UserImageScreen::OnSyncTimeout() {
137   sync_timer_.reset();
138   UserManager::Get()->GetUserImageManager()->GetSyncObserver()->
139       RemoveObserver(this);
140   if (is_screen_ready_)
141     HideCurtain();
142 }
143
144 bool UserImageScreen::IsWaitingForSync() const {
145   return sync_timer_.get() && sync_timer_->IsRunning();
146 }
147
148 void UserImageScreen::OnImageSelected(const std::string& image_type,
149                                       const std::string& image_url,
150                                       bool is_user_selection) {
151   if (is_user_selection) {
152     user_has_selected_image_ = true;
153   }
154   if (image_url.empty())
155     return;
156   int user_image_index = User::kInvalidImageIndex;
157   if (image_type == "default" &&
158       IsDefaultImageUrl(image_url, &user_image_index)) {
159     selected_image_ = user_image_index;
160   } else if (image_type == "camera") {
161     selected_image_ = User::kExternalImageIndex;
162   } else if (image_type == "profile") {
163     selected_image_ = User::kProfileImageIndex;
164   } else {
165     NOTREACHED() << "Unexpected image type: " << image_type;
166   }
167 }
168
169 void UserImageScreen::OnImageAccepted() {
170   UserManager* user_manager = UserManager::Get();
171   UserImageManager* image_manager = user_manager->GetUserImageManager();
172   std::string user_id = GetUser()->email();
173   int uma_index = 0;
174   switch (selected_image_) {
175     case User::kExternalImageIndex:
176       // Photo decoding may not have been finished yet.
177       if (user_photo_.isNull()) {
178         accept_photo_after_decoding_ = true;
179         return;
180       }
181       image_manager->
182           SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_));
183       uma_index = kHistogramImageFromCamera;
184       break;
185     case User::kProfileImageIndex:
186       image_manager->SaveUserImageFromProfileImage(user_id);
187       uma_index = kHistogramImageFromProfile;
188       break;
189     default:
190       DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
191       image_manager->SaveUserDefaultImageIndex(user_id, selected_image_);
192       uma_index = GetDefaultImageHistogramValue(selected_image_);
193       break;
194   }
195   if (user_has_selected_image_) {
196     UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
197                               uma_index,
198                               kHistogramImagesCount);
199   }
200   get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
201 }
202
203
204 void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled) {
205   if (profile_picture_enabled_ == profile_picture_enabled)
206     return;
207   profile_picture_enabled_ = profile_picture_enabled;
208   if (profile_picture_enabled) {
209     registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
210         content::NotificationService::AllSources());
211     registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
212         content::NotificationService::AllSources());
213   } else {
214     registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
215         content::NotificationService::AllSources());
216     registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
217         content::NotificationService::AllSources());
218   }
219   if (actor_)
220     actor_->SetProfilePictureEnabled(profile_picture_enabled);
221 }
222
223 void UserImageScreen::SetUserID(const std::string& user_id) {
224   DCHECK(!user_id.empty());
225   user_id_ = user_id;
226 }
227
228 void UserImageScreen::PrepareToShow() {
229   if (actor_)
230     actor_->PrepareToShow();
231 }
232
233 const User* UserImageScreen::GetUser() {
234   if (user_id_.empty())
235     return UserManager::Get()->GetLoggedInUser();
236   const User* user = UserManager::Get()->FindUser(user_id_);
237   DCHECK(user);
238   return user;
239 }
240
241 void UserImageScreen::Show() {
242   if (!actor_)
243     return;
244   if (GetUser()->CanSyncImage()) {
245     if (UserImageSyncObserver* sync_observer =
246           UserManager::Get()->GetUserImageManager()->GetSyncObserver()) {
247       // We have synced image already.
248       if (sync_observer->is_synced()) {
249         get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
250         return;
251       }
252       sync_observer->AddObserver(this);
253       sync_timer_.reset(new base::Timer(
254             FROM_HERE,
255             base::TimeDelta::FromSeconds(kSyncTimeoutSeconds),
256             base::Bind(&UserImageScreen::OnSyncTimeout, base::Unretained(this)),
257             false));
258       sync_timer_->Reset();
259     }
260   }
261   actor_->Show();
262   actor_->SetProfilePictureEnabled(profile_picture_enabled_);
263
264   selected_image_ = GetUser()->image_index();
265   actor_->SelectImage(selected_image_);
266
267   if (profile_picture_enabled_) {
268     // Start fetching the profile image.
269     UserManager::Get()->GetUserImageManager()->
270         DownloadProfileImage(kProfileDownloadReason);
271   }
272 }
273
274 void UserImageScreen::Hide() {
275   if (actor_)
276     actor_->Hide();
277 }
278
279 std::string UserImageScreen::GetName() const {
280   return WizardController::kUserImageScreenName;
281 }
282
283 void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) {
284   if (actor_ == actor)
285     actor_ = NULL;
286 }
287
288 void UserImageScreen::Observe(int type,
289                               const content::NotificationSource& source,
290                               const content::NotificationDetails& details) {
291   DCHECK(profile_picture_enabled_);
292   switch (type) {
293     case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: {
294       // We've got a new profile image.
295       profile_picture_data_url_ = webui::GetBitmapDataUrl(
296           *content::Details<const gfx::ImageSkia>(details).ptr()->bitmap());
297       if (actor_)
298         actor_->SendProfileImage(profile_picture_data_url_);
299       break;
300     }
301     case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: {
302       // User has a default profile image or fetching profile image has failed.
303       profile_picture_absent_ = true;
304       if (actor_)
305         actor_->OnProfileImageAbsent();
306       break;
307     }
308     case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
309       if (actor_)
310         actor_->SelectImage(GetUser()->image_index());
311       break;
312     }
313     default:
314       NOTREACHED();
315   }
316 }
317
318 bool UserImageScreen::profile_picture_absent() {
319   return profile_picture_absent_;
320 }
321
322 int UserImageScreen::selected_image() {
323   return selected_image_;
324 }
325
326 std::string UserImageScreen::profile_picture_data_url() {
327   return profile_picture_data_url_;
328 }
329
330 }  // namespace chromeos