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.
4
5#include "chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h"
6
7#include "ash/audio/sounds.h"
8#include "base/command_line.h"
9#include "base/logging.h"
10#include "base/metrics/histogram.h"
11#include "base/values.h"
12#include "chrome/browser/chromeos/login/existing_user_controller.h"
13#include "chrome/browser/chromeos/login/ui/webui_login_display.h"
14#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
15#include "chrome/common/chrome_switches.h"
16#include "chrome/common/url_constants.h"
17#include "chrome/grit/generated_resources.h"
18#include "chromeos/audio/chromeos_sounds.h"
19#include "components/user_manager/user.h"
20#include "components/user_manager/user_image/default_user_images.h"
21#include "grit/browser_resources.h"
22#include "net/base/data_url.h"
23#include "ui/base/l10n/l10n_util.h"
24#include "ui/base/resource/resource_bundle.h"
25#include "url/gurl.h"
26
27namespace {
28
29const char kJsScreenPath[] = "login.UserImageScreen";
30
31}  // namespace
32
33namespace chromeos {
34
35UserImageScreenHandler::UserImageScreenHandler()
36    : BaseScreenHandler(kJsScreenPath),
37      screen_(NULL),
38      show_on_init_(false),
39      is_ready_(false) {
40  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
41  media::SoundsManager* manager = media::SoundsManager::Get();
42  manager->Initialize(SOUND_OBJECT_DELETE,
43                      bundle.GetRawDataResource(IDR_SOUND_OBJECT_DELETE_WAV));
44  manager->Initialize(SOUND_CAMERA_SNAP,
45                      bundle.GetRawDataResource(IDR_SOUND_CAMERA_SNAP_WAV));
46}
47
48UserImageScreenHandler::~UserImageScreenHandler() {
49  if (screen_) {
50    screen_->OnActorDestroyed(this);
51  }
52}
53
54void UserImageScreenHandler::Initialize() {
55  if (show_on_init_) {
56    Show();
57    show_on_init_ = false;
58  }
59}
60
61void UserImageScreenHandler::SetDelegate(
62    UserImageScreenActor::Delegate* screen) {
63  screen_ = screen;
64}
65
66void UserImageScreenHandler::Show() {
67  if (!page_is_ready()) {
68    show_on_init_ = true;
69    return;
70  }
71  screen_show_time_ = base::Time::Now();
72  ShowScreen(OobeUI::kScreenUserImagePicker, NULL);
73
74  // When shown, query camera presence.
75  if (!screen_)
76    return;
77  if (is_ready_)
78    screen_->OnScreenReady();
79}
80
81void UserImageScreenHandler::Hide() {
82}
83
84void UserImageScreenHandler::PrepareToShow() {
85}
86
87void UserImageScreenHandler::DeclareLocalizedValues(
88    LocalizedValuesBuilder* builder) {
89  builder->Add("userImageScreenTitle", IDS_USER_IMAGE_SCREEN_TITLE);
90  builder->Add("userImageScreenDescription",
91               IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT);
92  builder->Add("takePhoto", IDS_OPTIONS_CHANGE_PICTURE_TAKE_PHOTO);
93  builder->Add("discardPhoto", IDS_OPTIONS_CHANGE_PICTURE_DISCARD_PHOTO);
94  builder->Add("flipPhoto", IDS_OPTIONS_CHANGE_PICTURE_FLIP_PHOTO);
95  builder->Add("profilePhoto", IDS_IMAGE_SCREEN_PROFILE_PHOTO);
96  builder->Add("profilePhotoLoading",
97               IDS_IMAGE_SCREEN_PROFILE_LOADING_PHOTO);
98  builder->Add("okButtonText", IDS_OK);
99  builder->Add("authorCredit", IDS_OPTIONS_SET_WALLPAPER_AUTHOR_TEXT);
100  builder->Add("photoFromCamera", IDS_OPTIONS_CHANGE_PICTURE_PHOTO_FROM_CAMERA);
101  builder->Add("photoFlippedAccessibleText",
102               IDS_OPTIONS_PHOTO_FLIP_ACCESSIBLE_TEXT);
103  builder->Add("photoFlippedBackAccessibleText",
104               IDS_OPTIONS_PHOTO_FLIPBACK_ACCESSIBLE_TEXT);
105  builder->Add("photoCaptureAccessibleText",
106               IDS_OPTIONS_PHOTO_CAPTURE_ACCESSIBLE_TEXT);
107  builder->Add("photoDiscardAccessibleText",
108               IDS_OPTIONS_PHOTO_DISCARD_ACCESSIBLE_TEXT);
109  builder->Add("syncingPreferences", IDS_IMAGE_SCREEN_SYNCING_PREFERENCES);
110}
111
112void UserImageScreenHandler::RegisterMessages() {
113  AddCallback("getImages", &UserImageScreenHandler::HandleGetImages);
114  AddCallback("screenReady", &UserImageScreenHandler::HandleScreenReady);
115  AddCallback("takePhoto", &UserImageScreenHandler::HandleTakePhoto);
116  AddCallback("discardPhoto", &UserImageScreenHandler::HandleDiscardPhoto);
117  AddCallback("photoTaken", &UserImageScreenHandler::HandlePhotoTaken);
118  AddCallback("selectImage", &UserImageScreenHandler::HandleSelectImage);
119  AddCallback("onUserImageAccepted",
120              &UserImageScreenHandler::HandleImageAccepted);
121  AddCallback("onUserImageScreenShown",
122              &UserImageScreenHandler::HandleScreenShown);
123}
124
125void UserImageScreenHandler::SelectImage(int index) {
126  if (page_is_ready())
127    CallJS("setSelectedImage", user_manager::GetDefaultImageUrl(index));
128}
129
130void UserImageScreenHandler::SendProfileImage(const std::string& data_url) {
131  if (page_is_ready())
132    CallJS("setProfileImage", data_url);
133}
134
135void UserImageScreenHandler::OnProfileImageAbsent() {
136  if (page_is_ready()) {
137    scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
138    CallJS("setProfileImage", *null_value);
139  }
140}
141
142// TODO(antrim) : It looks more like parameters for "Init" rather than callback.
143void UserImageScreenHandler::HandleGetImages() {
144  base::ListValue image_urls;
145  for (int i = user_manager::kFirstDefaultImageIndex;
146       i < user_manager::kDefaultImagesCount;
147       ++i) {
148    scoped_ptr<base::DictionaryValue> image_data(new base::DictionaryValue);
149    image_data->SetString("url", user_manager::GetDefaultImageUrl(i));
150    image_data->SetString(
151        "author",
152        l10n_util::GetStringUTF16(user_manager::kDefaultImageAuthorIDs[i]));
153    image_data->SetString(
154        "website",
155        l10n_util::GetStringUTF16(user_manager::kDefaultImageWebsiteIDs[i]));
156    image_data->SetString("title", user_manager::GetDefaultImageDescription(i));
157    image_urls.Append(image_data.release());
158  }
159  CallJS("setDefaultImages", image_urls);
160  if (!screen_)
161    return;
162  if (screen_->selected_image() != user_manager::User::USER_IMAGE_INVALID)
163    SelectImage(screen_->selected_image());
164
165  if (screen_->profile_picture_data_url() != url::kAboutBlankURL)
166    SendProfileImage(screen_->profile_picture_data_url());
167  else if (screen_->profile_picture_absent())
168    OnProfileImageAbsent();
169}
170
171void UserImageScreenHandler::HandleScreenReady() {
172  is_ready_ = true;
173  if (screen_)
174    screen_->OnScreenReady();
175}
176
177void UserImageScreenHandler::HandlePhotoTaken(const std::string& image_url) {
178  std::string mime_type, charset, raw_data;
179  if (!net::DataURL::Parse(GURL(image_url), &mime_type, &charset, &raw_data))
180    NOTREACHED();
181  DCHECK_EQ("image/png", mime_type);
182
183  if (screen_)
184    screen_->OnPhotoTaken(raw_data);
185}
186
187void UserImageScreenHandler::HandleTakePhoto() {
188  ash::PlaySystemSoundIfSpokenFeedback(SOUND_CAMERA_SNAP);
189}
190
191void UserImageScreenHandler::HandleDiscardPhoto() {
192  ash::PlaySystemSoundIfSpokenFeedback(SOUND_OBJECT_DELETE);
193}
194
195void UserImageScreenHandler::HandleSelectImage(const std::string& image_url,
196                                               const std::string& image_type,
197                                               bool is_user_selection) {
198  if (screen_)
199    screen_->OnImageSelected(image_type, image_url, is_user_selection);
200}
201
202void UserImageScreenHandler::HandleImageAccepted() {
203  if (screen_)
204    screen_->OnImageAccepted();
205}
206
207void UserImageScreenHandler::HandleScreenShown() {
208  DCHECK(!screen_show_time_.is_null());
209
210  base::TimeDelta delta = base::Time::Now() - screen_show_time_;
211  VLOG(1) << "Screen load time: " << delta.InSecondsF();
212  UMA_HISTOGRAM_TIMES("UserImage.ScreenIsShownTime", delta);
213}
214
215void UserImageScreenHandler::SetCameraPresent(bool present) {
216  CallJS("setCameraPresent", present);
217}
218
219void UserImageScreenHandler::HideCurtain() {
220  CallJS("hideCurtain");
221}
222
223}  // namespace chromeos
224