Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / webui / options / chromeos / change_picture_options_handler.cc
blobb6de55d1750d51808958ee0b7782aecfd3559d9f
1 // Copyright (c) 2013 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/ui/webui/options/chromeos/change_picture_options_handler.h"
7 #include "ash/audio/sounds.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/command_line.h"
11 #include "base/metrics/histogram.h"
12 #include "base/path_service.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chromeos/camera_presence_notifier.h"
18 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
19 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
20 #include "chrome/browser/chromeos/profiles/profile_helper.h"
21 #include "chrome/browser/ui/browser_finder.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/browser/ui/chrome_select_file_policy.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "chromeos/audio/chromeos_sounds.h"
29 #include "components/user_manager/user.h"
30 #include "components/user_manager/user_image/default_user_images.h"
31 #include "components/user_manager/user_image/user_image.h"
32 #include "components/user_manager/user_manager.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_service.h"
35 #include "content/public/browser/web_ui.h"
36 #include "content/public/common/url_constants.h"
37 #include "grit/browser_resources.h"
38 #include "net/base/data_url.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/base/webui/web_ui_util.h"
42 #include "ui/views/widget/widget.h"
43 #include "url/gurl.h"
45 using content::BrowserThread;
47 namespace chromeos {
48 namespace options {
50 namespace {
52 // Returns info about extensions for files we support as user images.
53 ui::SelectFileDialog::FileTypeInfo GetUserImageFileTypeInfo() {
54 ui::SelectFileDialog::FileTypeInfo file_type_info;
55 file_type_info.extensions.resize(1);
57 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("bmp"));
59 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("jpg"));
60 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("jpeg"));
62 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("png"));
64 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("tif"));
65 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("tiff"));
67 file_type_info.extension_description_overrides.resize(1);
68 file_type_info.extension_description_overrides[0] =
69 l10n_util::GetStringUTF16(IDS_IMAGE_FILES);
71 return file_type_info;
74 // Time histogram suffix for profile image download.
75 const char kProfileDownloadReason[] = "Preferences";
77 } // namespace
79 ChangePictureOptionsHandler::ChangePictureOptionsHandler()
80 : previous_image_url_(url::kAboutBlankURL),
81 previous_image_index_(user_manager::User::USER_IMAGE_INVALID) {
82 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
83 content::NotificationService::AllSources());
84 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
85 content::NotificationService::AllSources());
86 registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
87 content::NotificationService::AllSources());
89 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
90 media::SoundsManager* manager = media::SoundsManager::Get();
91 manager->Initialize(SOUND_OBJECT_DELETE,
92 bundle.GetRawDataResource(IDR_SOUND_OBJECT_DELETE_WAV));
93 manager->Initialize(SOUND_CAMERA_SNAP,
94 bundle.GetRawDataResource(IDR_SOUND_CAMERA_SNAP_WAV));
97 ChangePictureOptionsHandler::~ChangePictureOptionsHandler() {
98 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
99 if (select_file_dialog_.get())
100 select_file_dialog_->ListenerDestroyed();
103 void ChangePictureOptionsHandler::GetLocalizedValues(
104 base::DictionaryValue* localized_strings) {
105 DCHECK(localized_strings);
106 localized_strings->SetString("changePicturePage",
107 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TITLE));
108 localized_strings->SetString("changePicturePageDescription",
109 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT));
110 localized_strings->SetString("takePhoto",
111 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_TAKE_PHOTO));
112 localized_strings->SetString("discardPhoto",
113 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_DISCARD_PHOTO));
114 localized_strings->SetString("flipPhoto",
115 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_FLIP_PHOTO));
116 localized_strings->SetString("chooseFile",
117 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_CHOOSE_FILE));
118 localized_strings->SetString("profilePhoto",
119 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_PROFILE_PHOTO));
120 localized_strings->SetString("profilePhotoLoading",
121 l10n_util::GetStringUTF16(
122 IDS_OPTIONS_CHANGE_PICTURE_PROFILE_LOADING_PHOTO));
123 localized_strings->SetString("previewAltText",
124 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_PREVIEW_ALT));
125 localized_strings->SetString("authorCredit",
126 l10n_util::GetStringUTF16(IDS_OPTIONS_SET_WALLPAPER_AUTHOR_TEXT));
127 localized_strings->SetString("photoFromCamera",
128 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_PHOTO_FROM_CAMERA));
129 localized_strings->SetString("photoFlippedAccessibleText",
130 l10n_util::GetStringUTF16(IDS_OPTIONS_PHOTO_FLIP_ACCESSIBLE_TEXT));
131 localized_strings->SetString("photoFlippedBackAccessibleText",
132 l10n_util::GetStringUTF16(IDS_OPTIONS_PHOTO_FLIPBACK_ACCESSIBLE_TEXT));
133 localized_strings->SetString("photoCaptureAccessibleText",
134 l10n_util::GetStringUTF16(IDS_OPTIONS_PHOTO_CAPTURE_ACCESSIBLE_TEXT));
135 localized_strings->SetString("photoDiscardAccessibleText",
136 l10n_util::GetStringUTF16(IDS_OPTIONS_PHOTO_DISCARD_ACCESSIBLE_TEXT));
139 void ChangePictureOptionsHandler::RegisterMessages() {
140 web_ui()->RegisterMessageCallback("chooseFile",
141 base::Bind(&ChangePictureOptionsHandler::HandleChooseFile,
142 base::Unretained(this)));
143 web_ui()->RegisterMessageCallback("takePhoto",
144 base::Bind(&ChangePictureOptionsHandler::HandleTakePhoto,
145 base::Unretained(this)));
146 web_ui()->RegisterMessageCallback("photoTaken",
147 base::Bind(&ChangePictureOptionsHandler::HandlePhotoTaken,
148 base::Unretained(this)));
149 web_ui()->RegisterMessageCallback("discardPhoto",
150 base::Bind(&ChangePictureOptionsHandler::HandleDiscardPhoto,
151 base::Unretained(this)));
152 web_ui()->RegisterMessageCallback("onChangePicturePageShown",
153 base::Bind(&ChangePictureOptionsHandler::HandlePageShown,
154 base::Unretained(this)));
155 web_ui()->RegisterMessageCallback("onChangePicturePageHidden",
156 base::Bind(&ChangePictureOptionsHandler::HandlePageHidden,
157 base::Unretained(this)));
158 web_ui()->RegisterMessageCallback("onChangePicturePageInitialized",
159 base::Bind(&ChangePictureOptionsHandler::HandlePageInitialized,
160 base::Unretained(this)));
161 web_ui()->RegisterMessageCallback("selectImage",
162 base::Bind(&ChangePictureOptionsHandler::HandleSelectImage,
163 base::Unretained(this)));
166 void ChangePictureOptionsHandler::SendDefaultImages() {
167 base::ListValue image_urls;
168 for (int i = user_manager::kFirstDefaultImageIndex;
169 i < user_manager::kDefaultImagesCount;
170 ++i) {
171 scoped_ptr<base::DictionaryValue> image_data(new base::DictionaryValue);
172 image_data->SetString("url", user_manager::GetDefaultImageUrl(i));
173 image_data->SetString(
174 "author",
175 l10n_util::GetStringUTF16(user_manager::kDefaultImageAuthorIDs[i]));
176 image_data->SetString(
177 "website",
178 l10n_util::GetStringUTF16(user_manager::kDefaultImageWebsiteIDs[i]));
179 image_data->SetString("title", user_manager::GetDefaultImageDescription(i));
180 image_urls.Append(image_data.release());
182 web_ui()->CallJavascriptFunction("ChangePictureOptions.setDefaultImages",
183 image_urls);
186 void ChangePictureOptionsHandler::HandleChooseFile(
187 const base::ListValue* args) {
188 DCHECK(args && args->empty());
189 select_file_dialog_ = ui::SelectFileDialog::Create(
190 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
192 base::FilePath downloads_path;
193 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &downloads_path)) {
194 NOTREACHED();
195 return;
198 // Static so we initialize it only once.
199 CR_DEFINE_STATIC_LOCAL(ui::SelectFileDialog::FileTypeInfo, file_type_info,
200 (GetUserImageFileTypeInfo()));
202 select_file_dialog_->SelectFile(
203 ui::SelectFileDialog::SELECT_OPEN_FILE,
204 l10n_util::GetStringUTF16(IDS_DOWNLOAD_TITLE),
205 downloads_path,
206 &file_type_info,
208 FILE_PATH_LITERAL(""),
209 GetBrowserWindow(),
210 NULL);
213 void ChangePictureOptionsHandler::HandleTakePhoto(
214 const base::ListValue* args) {
215 DCHECK(args->empty());
216 ash::PlaySystemSoundIfSpokenFeedback(SOUND_CAMERA_SNAP);
219 void ChangePictureOptionsHandler::HandleDiscardPhoto(
220 const base::ListValue* args) {
221 DCHECK(args->empty());
222 ash::PlaySystemSoundIfSpokenFeedback(SOUND_OBJECT_DELETE);
225 void ChangePictureOptionsHandler::HandlePhotoTaken(
226 const base::ListValue* args) {
227 DCHECK_CURRENTLY_ON(BrowserThread::UI);
228 std::string image_url;
229 if (!args || args->GetSize() != 1 || !args->GetString(0, &image_url))
230 NOTREACHED();
231 DCHECK(!image_url.empty());
233 std::string mime_type, charset, raw_data;
234 if (!net::DataURL::Parse(GURL(image_url), &mime_type, &charset, &raw_data))
235 NOTREACHED();
236 DCHECK_EQ("image/png", mime_type);
238 user_photo_ = gfx::ImageSkia();
239 user_photo_data_url_ = image_url;
241 ImageDecoder::Cancel(this);
242 ImageDecoder::Start(this, raw_data);
245 void ChangePictureOptionsHandler::HandlePageInitialized(
246 const base::ListValue* args) {
247 DCHECK(args && args->empty());
248 SendDefaultImages();
251 void ChangePictureOptionsHandler::HandlePageShown(const base::ListValue* args) {
252 DCHECK(args && args->empty());
253 SendSelectedImage();
254 UpdateProfileImage();
255 CameraPresenceNotifier::GetInstance()->AddObserver(this);
258 void ChangePictureOptionsHandler::HandlePageHidden(
259 const base::ListValue* args) {
260 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
263 void ChangePictureOptionsHandler::SendSelectedImage() {
264 const user_manager::User* user = GetUser();
265 DCHECK(!user->email().empty());
267 previous_image_index_ = user->image_index();
268 switch (previous_image_index_) {
269 case user_manager::User::USER_IMAGE_EXTERNAL: {
270 // User has image from camera/file, record it and add to the image list.
271 previous_image_ = user->GetImage();
272 SendOldImage(webui::GetBitmapDataUrl(*previous_image_.bitmap()));
273 break;
275 case user_manager::User::USER_IMAGE_PROFILE: {
276 // User has his/her Profile image as the current image.
277 SendProfileImage(user->GetImage(), true);
278 break;
280 default: {
281 DCHECK(previous_image_index_ >= 0 &&
282 previous_image_index_ < user_manager::kDefaultImagesCount);
283 if (previous_image_index_ >= user_manager::kFirstDefaultImageIndex) {
284 // User has image from the current set of default images.
285 base::StringValue image_url(
286 user_manager::GetDefaultImageUrl(previous_image_index_));
287 web_ui()->CallJavascriptFunction(
288 "ChangePictureOptions.setSelectedImage", image_url);
289 } else {
290 // User has an old default image, so present it in the same manner as a
291 // previous image from file.
292 SendOldImage(user_manager::GetDefaultImageUrl(previous_image_index_));
298 void ChangePictureOptionsHandler::SendProfileImage(const gfx::ImageSkia& image,
299 bool should_select) {
300 base::StringValue data_url(webui::GetBitmapDataUrl(*image.bitmap()));
301 base::FundamentalValue select(should_select);
302 web_ui()->CallJavascriptFunction("ChangePictureOptions.setProfileImage",
303 data_url, select);
306 void ChangePictureOptionsHandler::UpdateProfileImage() {
307 UserImageManager* user_image_manager =
308 ChromeUserManager::Get()->GetUserImageManager(GetUser()->email());
309 // If we have a downloaded profile image and haven't sent it in
310 // |SendSelectedImage|, send it now (without selecting).
311 if (previous_image_index_ != user_manager::User::USER_IMAGE_PROFILE &&
312 !user_image_manager->DownloadedProfileImage().isNull())
313 SendProfileImage(user_image_manager->DownloadedProfileImage(), false);
315 user_image_manager->DownloadProfileImage(kProfileDownloadReason);
318 void ChangePictureOptionsHandler::SendOldImage(const std::string& image_url) {
319 previous_image_url_ = image_url;
320 base::StringValue url(image_url);
321 web_ui()->CallJavascriptFunction("ChangePictureOptions.setOldImage", url);
324 void ChangePictureOptionsHandler::HandleSelectImage(
325 const base::ListValue* args) {
326 std::string image_url;
327 std::string image_type;
328 if (!args ||
329 args->GetSize() != 2 ||
330 !args->GetString(0, &image_url) ||
331 !args->GetString(1, &image_type)) {
332 NOTREACHED();
333 return;
335 DCHECK(!image_url.empty());
336 DCHECK(!image_type.empty());
338 UserImageManager* user_image_manager =
339 ChromeUserManager::Get()->GetUserImageManager(GetUser()->email());
340 int image_index = user_manager::User::USER_IMAGE_INVALID;
341 bool waiting_for_camera_photo = false;
343 if (image_type == "old") {
344 // Previous image (from camera or manually uploaded) re-selected.
345 DCHECK(!previous_image_.isNull());
346 user_image_manager->SaveUserImage(
347 user_manager::UserImage::CreateAndEncode(previous_image_));
349 UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
350 user_manager::kHistogramImageOld,
351 user_manager::kHistogramImagesCount);
352 VLOG(1) << "Selected old user image";
353 } else if (image_type == "default" &&
354 user_manager::IsDefaultImageUrl(image_url, &image_index)) {
355 // One of the default user images.
356 user_image_manager->SaveUserDefaultImageIndex(image_index);
358 UMA_HISTOGRAM_ENUMERATION(
359 "UserImage.ChangeChoice",
360 user_manager::GetDefaultImageHistogramValue(image_index),
361 user_manager::kHistogramImagesCount);
362 VLOG(1) << "Selected default user image: " << image_index;
363 } else if (image_type == "camera") {
364 // Camera image is selected.
365 if (user_photo_.isNull()) {
366 waiting_for_camera_photo = true;
367 VLOG(1) << "Still waiting for camera image to decode";
368 } else {
369 SetImageFromCamera(user_photo_);
371 } else if (image_type == "profile") {
372 // Profile image selected. Could be previous (old) user image.
373 user_image_manager->SaveUserImageFromProfileImage();
375 if (previous_image_index_ == user_manager::User::USER_IMAGE_PROFILE) {
376 UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
377 user_manager::kHistogramImageOld,
378 user_manager::kHistogramImagesCount);
379 VLOG(1) << "Selected old (profile) user image";
380 } else {
381 UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
382 user_manager::kHistogramImageFromProfile,
383 user_manager::kHistogramImagesCount);
384 VLOG(1) << "Selected profile image";
386 } else {
387 NOTREACHED() << "Unexpected image type: " << image_type;
390 // Ignore the result of the previous decoding if it's no longer needed.
391 if (!waiting_for_camera_photo)
392 ImageDecoder::Cancel(this);
395 void ChangePictureOptionsHandler::FileSelected(const base::FilePath& path,
396 int index,
397 void* params) {
398 ChromeUserManager::Get()
399 ->GetUserImageManager(GetUser()->email())
400 ->SaveUserImageFromFile(path);
401 UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
402 user_manager::kHistogramImageFromFile,
403 user_manager::kHistogramImagesCount);
404 VLOG(1) << "Selected image from file";
407 void ChangePictureOptionsHandler::SetImageFromCamera(
408 const gfx::ImageSkia& photo) {
409 ChromeUserManager::Get()
410 ->GetUserImageManager(GetUser()->email())
411 ->SaveUserImage(user_manager::UserImage::CreateAndEncode(photo));
412 UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
413 user_manager::kHistogramImageFromCamera,
414 user_manager::kHistogramImagesCount);
415 VLOG(1) << "Selected camera photo";
418 void ChangePictureOptionsHandler::SetCameraPresent(bool present) {
419 base::FundamentalValue present_value(present);
421 web_ui()->CallJavascriptFunction("ChangePictureOptions.setCameraPresent",
422 present_value);
425 void ChangePictureOptionsHandler::OnCameraPresenceCheckDone(
426 bool is_camera_present) {
427 SetCameraPresent(is_camera_present);
430 void ChangePictureOptionsHandler::Observe(
431 int type,
432 const content::NotificationSource& source,
433 const content::NotificationDetails& details) {
434 if (type == chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED) {
435 // User profile image has been updated.
436 SendProfileImage(*content::Details<const gfx::ImageSkia>(details).ptr(),
437 false);
438 } else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) {
439 // Not initialized yet.
440 if (previous_image_index_ == user_manager::User::USER_IMAGE_INVALID)
441 return;
442 SendSelectedImage();
446 gfx::NativeWindow ChangePictureOptionsHandler::GetBrowserWindow() const {
447 Browser* browser =
448 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents());
449 return browser->window()->GetNativeWindow();
452 void ChangePictureOptionsHandler::OnImageDecoded(
453 const SkBitmap& decoded_image) {
454 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
455 SetImageFromCamera(user_photo_);
458 void ChangePictureOptionsHandler::OnDecodeImageFailed() {
459 NOTREACHED() << "Failed to decode PNG image from WebUI";
462 const user_manager::User* ChangePictureOptionsHandler::GetUser() const {
463 Profile* profile = Profile::FromWebUI(web_ui());
464 const user_manager::User* user =
465 ProfileHelper::Get()->GetUserByProfile(profile);
466 if (!user)
467 return user_manager::UserManager::Get()->GetActiveUser();
468 return user;
471 } // namespace options
472 } // namespace chromeos