Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / chromeos / login / screens / user_image_screen.cc
blob780554364c1e960592c28d09f05a4c5ed87a1709
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.
5 #include "chrome/browser/chromeos/login/screens/user_image_screen.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/compiler_specific.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/timer/timer.h"
17 #include "base/values.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
20 #include "chrome/browser/chromeos/camera_presence_notifier.h"
21 #include "chrome/browser/chromeos/login/screen_manager.h"
22 #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
23 #include "chrome/browser/chromeos/login/screens/user_image_view.h"
24 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
25 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
26 #include "chrome/browser/chromeos/login/wizard_controller.h"
27 #include "chrome/browser/chromeos/profiles/profile_helper.h"
28 #include "chrome/browser/policy/profile_policy_connector.h"
29 #include "chrome/browser/policy/profile_policy_connector_factory.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "components/policy/core/common/policy_map.h"
32 #include "components/policy/core/common/policy_namespace.h"
33 #include "components/policy/core/common/policy_service.h"
34 #include "components/user_manager/user.h"
35 #include "components/user_manager/user_image/default_user_images.h"
36 #include "components/user_manager/user_image/user_image.h"
37 #include "components/user_manager/user_manager.h"
38 #include "content/public/browser/browser_thread.h"
39 #include "content/public/browser/notification_service.h"
40 #include "policy/policy_constants.h"
41 #include "third_party/skia/include/core/SkBitmap.h"
42 #include "ui/base/webui/web_ui_util.h"
43 #include "ui/gfx/image/image_skia.h"
45 using content::BrowserThread;
47 namespace chromeos {
49 namespace {
51 // Time histogram suffix for profile image download.
52 const char kProfileDownloadReason[] = "OOBE";
54 // Maximum amount of time to wait for the user image to sync.
55 // The screen is shown iff sync failed or time limit exceeded.
56 const int kSyncTimeoutSeconds = 10;
58 } // namespace
60 // static
61 UserImageScreen* UserImageScreen::Get(ScreenManager* manager) {
62 return static_cast<UserImageScreen*>(
63 manager->GetScreen(WizardController::kUserImageScreenName));
66 UserImageScreen::UserImageScreen(BaseScreenDelegate* base_screen_delegate,
67 UserImageView* view)
68 : UserImageModel(base_screen_delegate),
69 view_(view),
70 accept_photo_after_decoding_(false),
71 selected_image_(user_manager::User::USER_IMAGE_INVALID),
72 is_screen_ready_(false),
73 user_has_selected_image_(false) {
74 if (view_)
75 view_->Bind(*this);
76 notification_registrar_.Add(this,
77 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
78 content::NotificationService::AllSources());
79 notification_registrar_.Add(this,
80 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
81 content::NotificationService::AllSources());
82 notification_registrar_.Add(this,
83 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
84 content::NotificationService::AllSources());
85 GetContextEditor().SetString(kContextKeyProfilePictureDataURL, std::string());
88 UserImageScreen::~UserImageScreen() {
89 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
90 if (view_)
91 view_->Unbind();
94 void UserImageScreen::OnScreenReady() {
95 is_screen_ready_ = true;
96 if (!IsWaitingForSync())
97 HideCurtain();
100 void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
101 DCHECK_CURRENTLY_ON(BrowserThread::UI);
102 user_photo_ = gfx::ImageSkia();
103 ImageDecoder::Cancel(this);
104 ImageDecoder::Start(this, raw_data);
107 void UserImageScreen::OnCameraPresenceCheckDone(bool is_camera_present) {
108 GetContextEditor().SetBoolean(kContextKeyIsCameraPresent, is_camera_present);
111 void UserImageScreen::HideCurtain() {
112 // Skip user image selection for ephemeral users.
113 if (user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral(
114 GetUser()->GetUserID())) {
115 ExitScreen();
117 if (view_)
118 view_->HideCurtain();
121 void UserImageScreen::OnImageDecoded(const SkBitmap& decoded_image) {
122 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
123 if (accept_photo_after_decoding_)
124 OnImageAccepted();
127 void UserImageScreen::OnDecodeImageFailed() {
128 NOTREACHED() << "Failed to decode PNG image from WebUI";
131 void UserImageScreen::OnInitialSync(bool local_image_updated) {
132 DCHECK(sync_timer_);
133 ReportSyncResult(SyncResult::SUCCEEDED);
134 if (!local_image_updated) {
135 sync_timer_.reset();
136 GetSyncObserver()->RemoveObserver(this);
137 if (is_screen_ready_)
138 HideCurtain();
139 return;
141 ExitScreen();
144 void UserImageScreen::OnSyncTimeout() {
145 ReportSyncResult(SyncResult::TIMED_OUT);
146 sync_timer_.reset();
147 GetSyncObserver()->RemoveObserver(this);
148 if (is_screen_ready_)
149 HideCurtain();
152 bool UserImageScreen::IsWaitingForSync() const {
153 return sync_timer_.get() && sync_timer_->IsRunning();
156 void UserImageScreen::OnUserImagePolicyChanged(const base::Value* previous,
157 const base::Value* current) {
158 if (current) {
159 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
160 FROM_HERE, policy_registrar_.release());
161 ExitScreen();
165 void UserImageScreen::OnImageSelected(const std::string& image_type,
166 const std::string& image_url,
167 bool is_user_selection) {
168 if (is_user_selection) {
169 user_has_selected_image_ = true;
171 if (image_url.empty())
172 return;
173 int user_image_index = user_manager::User::USER_IMAGE_INVALID;
174 if (image_type == "default" &&
175 user_manager::IsDefaultImageUrl(image_url, &user_image_index)) {
176 selected_image_ = user_image_index;
177 } else if (image_type == "camera") {
178 selected_image_ = user_manager::User::USER_IMAGE_EXTERNAL;
179 } else if (image_type == "profile") {
180 selected_image_ = user_manager::User::USER_IMAGE_PROFILE;
181 } else {
182 NOTREACHED() << "Unexpected image type: " << image_type;
186 void UserImageScreen::OnImageAccepted() {
187 UserImageManager* image_manager = GetUserImageManager();
188 int uma_index = 0;
189 switch (selected_image_) {
190 case user_manager::User::USER_IMAGE_EXTERNAL:
191 // Photo decoding may not have been finished yet.
192 if (user_photo_.isNull()) {
193 accept_photo_after_decoding_ = true;
194 return;
196 image_manager->SaveUserImage(
197 user_manager::UserImage::CreateAndEncode(user_photo_));
198 uma_index = user_manager::kHistogramImageFromCamera;
199 break;
200 case user_manager::User::USER_IMAGE_PROFILE:
201 image_manager->SaveUserImageFromProfileImage();
202 uma_index = user_manager::kHistogramImageFromProfile;
203 break;
204 default:
205 DCHECK(selected_image_ >= 0 &&
206 selected_image_ < user_manager::kDefaultImagesCount);
207 image_manager->SaveUserDefaultImageIndex(selected_image_);
208 uma_index = user_manager::GetDefaultImageHistogramValue(selected_image_);
209 break;
211 if (user_has_selected_image_) {
212 UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
213 uma_index,
214 user_manager::kHistogramImagesCount);
216 ExitScreen();
220 void UserImageScreen::PrepareToShow() {
221 if (view_)
222 view_->PrepareToShow();
225 const user_manager::User* UserImageScreen::GetUser() {
226 return user_manager::UserManager::Get()->GetLoggedInUser();
229 UserImageManager* UserImageScreen::GetUserImageManager() {
230 return ChromeUserManager::Get()->GetUserImageManager(GetUser()->email());
233 UserImageSyncObserver* UserImageScreen::GetSyncObserver() {
234 return GetUserImageManager()->GetSyncObserver();
237 void UserImageScreen::Show() {
238 if (!view_)
239 return;
241 DCHECK(!policy_registrar_);
242 if (Profile* profile = ProfileHelper::Get()->GetProfileByUser(GetUser())) {
243 policy::PolicyService* policy_service =
244 policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile)
245 ->policy_service();
246 if (policy_service->GetPolicies(
247 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME,
248 std::string()))
249 .Get(policy::key::kUserAvatarImage)) {
250 // If the user image is managed by policy, skip the screen because the
251 // user is not allowed to override a policy-set image.
252 ExitScreen();
253 return;
256 // Listen for policy changes. If at any point, the user image becomes
257 // managed by policy, the screen will close.
258 policy_registrar_.reset(new policy::PolicyChangeRegistrar(
259 policy_service,
260 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
261 policy_registrar_->Observe(
262 policy::key::kUserAvatarImage,
263 base::Bind(&UserImageScreen::OnUserImagePolicyChanged,
264 base::Unretained(this)));
265 } else {
266 NOTREACHED();
269 if (GetUser()->CanSyncImage()) {
270 if (UserImageSyncObserver* sync_observer = GetSyncObserver()) {
271 sync_waiting_start_time_ = base::Time::Now();
272 // We have synced image already.
273 if (sync_observer->is_synced()) {
274 ReportSyncResult(SyncResult::SUCCEEDED);
275 ExitScreen();
276 return;
278 sync_observer->AddObserver(this);
279 sync_timer_.reset(new base::Timer(
280 FROM_HERE,
281 base::TimeDelta::FromSeconds(kSyncTimeoutSeconds),
282 base::Bind(&UserImageScreen::OnSyncTimeout, base::Unretained(this)),
283 false));
284 sync_timer_->Reset();
287 CameraPresenceNotifier::GetInstance()->AddObserver(this);
288 view_->Show();
290 selected_image_ = GetUser()->image_index();
291 GetContextEditor().SetString(
292 kContextKeySelectedImageURL,
293 user_manager::GetDefaultImageUrl(selected_image_));
295 // Start fetching the profile image.
296 GetUserImageManager()->DownloadProfileImage(kProfileDownloadReason);
299 void UserImageScreen::Hide() {
300 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
301 notification_registrar_.RemoveAll();
302 policy_registrar_.reset();
303 sync_timer_.reset();
304 if (UserImageSyncObserver* sync_observer = GetSyncObserver())
305 sync_observer->RemoveObserver(this);
306 if (view_)
307 view_->Hide();
310 void UserImageScreen::OnViewDestroyed(UserImageView* view) {
311 if (view_ == view)
312 view_ = nullptr;
315 void UserImageScreen::Observe(int type,
316 const content::NotificationSource& source,
317 const content::NotificationDetails& details) {
318 switch (type) {
319 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: {
320 // We've got a new profile image.
321 GetContextEditor().SetString(
322 kContextKeyProfilePictureDataURL,
323 webui::GetBitmapDataUrl(
324 *content::Details<const gfx::ImageSkia>(details)
325 .ptr()
326 ->bitmap()));
327 break;
329 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: {
330 // User has a default profile image or fetching profile image has failed.
331 GetContextEditor().SetString(kContextKeyProfilePictureDataURL,
332 std::string());
333 break;
335 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
336 GetContextEditor().SetString(
337 kContextKeySelectedImageURL,
338 user_manager::GetDefaultImageUrl(GetUser()->image_index()));
339 break;
341 default:
342 NOTREACHED();
346 void UserImageScreen::ExitScreen() {
347 policy_registrar_.reset();
348 sync_timer_.reset();
349 if (UserImageSyncObserver* sync_observer = GetSyncObserver())
350 sync_observer->RemoveObserver(this);
351 Finish(BaseScreenDelegate::USER_IMAGE_SELECTED);
354 void UserImageScreen::ReportSyncResult(SyncResult timed_out) const {
355 base::TimeDelta duration = base::Time::Now() - sync_waiting_start_time_;
356 UMA_HISTOGRAM_TIMES("Login.NewUserPriorityPrefsSyncTime", duration);
357 UMA_HISTOGRAM_ENUMERATION("Login.NewUserPriorityPrefsSyncResult",
358 static_cast<int>(timed_out),
359 static_cast<int>(SyncResult::COUNT));
362 } // namespace chromeos