1 // Copyright 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/create_profile_handler.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/value_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/managed_mode/managed_user_registration_utility.h"
16 #include "chrome/browser/managed_mode/managed_user_service.h"
17 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
18 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
19 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/profiles/profile_metrics.h"
22 #include "chrome/browser/profiles/profiles_state.h"
23 #include "chrome/browser/sync/profile_sync_service.h"
24 #include "chrome/browser/sync/profile_sync_service_factory.h"
25 #include "chrome/browser/ui/webui/options/options_handlers_helper.h"
26 #include "chrome/common/pref_names.h"
27 #include "grit/generated_resources.h"
28 #include "ui/base/l10n/l10n_util.h"
32 CreateProfileHandler::CreateProfileHandler()
33 : profile_creation_type_(NO_CREATION_IN_PROGRESS),
34 weak_ptr_factory_(this) {
37 CreateProfileHandler::~CreateProfileHandler() {
38 CancelProfileRegistration(false);
41 void CreateProfileHandler::GetLocalizedValues(
42 base::DictionaryValue* localized_strings) {
45 void CreateProfileHandler::RegisterMessages() {
46 web_ui()->RegisterMessageCallback(
47 "cancelCreateProfile",
48 base::Bind(&CreateProfileHandler::HandleCancelProfileCreation,
49 base::Unretained(this)));
50 web_ui()->RegisterMessageCallback(
52 base::Bind(&CreateProfileHandler::CreateProfile,
53 base::Unretained(this)));
56 void CreateProfileHandler::CreateProfile(const base::ListValue* args) {
57 // This handler could have been called in managed mode, for example because
58 // the user fiddled with the web inspector. Silently return in this case.
59 Profile* current_profile = Profile::FromWebUI(web_ui());
60 if (current_profile->IsManaged())
63 if (!profiles::IsMultipleProfilesEnabled())
66 // We can have only one in progress profile creation
67 // at any given moment, if new ones are initiated just
68 // ignore them until we are done with the old one.
69 if (profile_creation_type_ != NO_CREATION_IN_PROGRESS)
72 profile_creation_type_ = NON_SUPERVISED_PROFILE_CREATION;
74 DCHECK(profile_path_being_created_.empty());
75 profile_creation_start_time_ = base::TimeTicks::Now();
79 std::string managed_user_id;
80 bool create_shortcut = false;
81 bool managed_user = false;
82 if (args->GetString(0, &name) && args->GetString(1, &icon)) {
83 if (args->GetBoolean(2, &create_shortcut)) {
84 bool success = args->GetBoolean(3, &managed_user);
86 success = args->GetString(4, &managed_user_id);
92 if (!IsValidExistingManagedUserId(managed_user_id))
95 profile_creation_type_ = SUPERVISED_PROFILE_IMPORT;
96 if (managed_user_id.empty()) {
97 profile_creation_type_ = SUPERVISED_PROFILE_CREATION;
99 ManagedUserRegistrationUtility::GenerateNewManagedUserId();
101 // If sync is not yet fully initialized, the creation may take extra time,
102 // so show a message. Import doesn't wait for an acknowledgement, so it
103 // won't have the same potential delay.
104 ProfileSyncService* sync_service =
105 ProfileSyncServiceFactory::GetInstance()->GetForProfile(
107 ProfileSyncService::SyncStatusSummary status =
108 sync_service->QuerySyncStatusSummary();
109 if (status == ProfileSyncService::DATATYPES_NOT_INITIALIZED) {
110 ShowProfileCreationWarning(l10n_util::GetStringUTF16(
111 IDS_PROFILES_CREATE_MANAGED_JUST_SIGNED_IN));
116 ProfileMetrics::LogProfileAddNewUser(ProfileMetrics::ADD_NEW_USER_DIALOG);
118 profile_path_being_created_ = ProfileManager::CreateMultiProfileAsync(
120 base::Bind(&CreateProfileHandler::OnProfileCreated,
121 weak_ptr_factory_.GetWeakPtr(),
123 helper::GetDesktopType(web_ui()),
128 void CreateProfileHandler::OnProfileCreated(
129 bool create_shortcut,
130 chrome::HostDesktopType desktop_type,
131 const std::string& managed_user_id,
133 Profile::CreateStatus status) {
134 if (status != Profile::CREATE_STATUS_CREATED)
135 RecordProfileCreationMetrics(status);
138 case Profile::CREATE_STATUS_LOCAL_FAIL: {
139 ShowProfileCreationError(profile,
140 GetProfileCreationErrorMessage(LOCAL_ERROR));
143 case Profile::CREATE_STATUS_CREATED: {
144 // Do nothing for an intermediate status.
147 case Profile::CREATE_STATUS_INITIALIZED: {
148 HandleProfileCreationSuccess(create_shortcut, desktop_type,
149 managed_user_id, profile);
152 // User-initiated cancellation is handled in CancelProfileRegistration and
153 // does not call this callback.
154 case Profile::CREATE_STATUS_CANCELED:
155 // Managed user registration errors are handled in
156 // OnManagedUserRegistered().
157 case Profile::CREATE_STATUS_REMOTE_FAIL:
158 case Profile::MAX_CREATE_STATUS: {
165 void CreateProfileHandler::HandleProfileCreationSuccess(
166 bool create_shortcut,
167 chrome::HostDesktopType desktop_type,
168 const std::string& managed_user_id,
170 switch (profile_creation_type_) {
171 case NON_SUPERVISED_PROFILE_CREATION: {
172 DCHECK(managed_user_id.empty());
173 CreateShortcutAndShowSuccess(create_shortcut, desktop_type, profile);
176 case SUPERVISED_PROFILE_CREATION:
177 case SUPERVISED_PROFILE_IMPORT:
178 RegisterManagedUser(create_shortcut, desktop_type,
179 managed_user_id, profile);
181 case NO_CREATION_IN_PROGRESS:
187 void CreateProfileHandler::RegisterManagedUser(
188 bool create_shortcut,
189 chrome::HostDesktopType desktop_type,
190 const std::string& managed_user_id,
191 Profile* new_profile) {
192 DCHECK_EQ(profile_path_being_created_.value(),
193 new_profile->GetPath().value());
195 ManagedUserService* managed_user_service =
196 ManagedUserServiceFactory::GetForProfile(new_profile);
198 // Register the managed user using the profile of the custodian.
199 managed_user_registration_utility_ =
200 ManagedUserRegistrationUtility::Create(Profile::FromWebUI(web_ui()));
201 managed_user_service->RegisterAndInitSync(
202 managed_user_registration_utility_.get(),
203 Profile::FromWebUI(web_ui()),
205 base::Bind(&CreateProfileHandler::OnManagedUserRegistered,
206 weak_ptr_factory_.GetWeakPtr(),
212 void CreateProfileHandler::OnManagedUserRegistered(
213 bool create_shortcut,
214 chrome::HostDesktopType desktop_type,
216 const GoogleServiceAuthError& error) {
217 GoogleServiceAuthError::State state = error.state();
218 RecordSupervisedProfileCreationMetrics(state);
219 if (state == GoogleServiceAuthError::NONE) {
220 CreateShortcutAndShowSuccess(create_shortcut, desktop_type, profile);
224 base::string16 error_msg;
225 if (state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
226 state == GoogleServiceAuthError::USER_NOT_SIGNED_UP ||
227 state == GoogleServiceAuthError::ACCOUNT_DELETED ||
228 state == GoogleServiceAuthError::ACCOUNT_DISABLED) {
229 error_msg = GetProfileCreationErrorMessage(SIGNIN_ERROR);
231 error_msg = GetProfileCreationErrorMessage(REMOTE_ERROR);
233 ShowProfileCreationError(profile, error_msg);
236 void CreateProfileHandler::CreateShortcutAndShowSuccess(
237 bool create_shortcut,
238 chrome::HostDesktopType desktop_type,
240 if (create_shortcut) {
241 ProfileShortcutManager* shortcut_manager =
242 g_browser_process->profile_manager()->profile_shortcut_manager();
244 if (shortcut_manager)
245 shortcut_manager->CreateProfileShortcut(profile->GetPath());
248 DCHECK_EQ(profile_path_being_created_.value(), profile->GetPath().value());
249 profile_path_being_created_.clear();
250 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
251 base::DictionaryValue dict;
252 dict.SetString("name",
253 profile->GetPrefs()->GetString(prefs::kProfileName));
254 dict.Set("filePath", base::CreateFilePathValue(profile->GetPath()));
256 profile_creation_type_ == SUPERVISED_PROFILE_CREATION ||
257 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT;
258 dict.SetBoolean("isManaged", is_managed);
259 web_ui()->CallJavascriptFunction(
260 GetJavascriptMethodName(PROFILE_CREATION_SUCCESS), dict);
262 // If the new profile is a supervised user, instead of opening a new window
263 // right away, a confirmation overlay will be shown by JS from the creation
264 // dialog. If we are importing an existing supervised profile or creating a
265 // new non-supervised user profile we don't show any confirmation, so open
266 // the new window now.
267 if (profile_creation_type_ != SUPERVISED_PROFILE_CREATION) {
268 // Opening the new window must be the last action, after all callbacks
269 // have been run, to give them a chance to initialize the profile.
270 helper::OpenNewWindowForProfile(desktop_type,
272 Profile::CREATE_STATUS_INITIALIZED);
274 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
277 void CreateProfileHandler::ShowProfileCreationError(
279 const base::string16& error) {
280 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
281 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
282 profile_path_being_created_.clear();
283 web_ui()->CallJavascriptFunction(
284 GetJavascriptMethodName(PROFILE_CREATION_ERROR),
285 base::StringValue(error));
286 helper::DeleteProfileAtPath(profile->GetPath(), web_ui());
289 void CreateProfileHandler::ShowProfileCreationWarning(
290 const base::string16& warning) {
291 DCHECK_EQ(SUPERVISED_PROFILE_CREATION, profile_creation_type_);
292 web_ui()->CallJavascriptFunction("BrowserOptions.showCreateProfileWarning",
293 base::StringValue(warning));
296 void CreateProfileHandler::HandleCancelProfileCreation(
297 const base::ListValue* args) {
298 CancelProfileRegistration(true);
301 void CreateProfileHandler::CancelProfileRegistration(bool user_initiated) {
302 if (profile_path_being_created_.empty())
305 ProfileManager* manager = g_browser_process->profile_manager();
306 Profile* new_profile = manager->GetProfileByPath(profile_path_being_created_);
310 // Non-managed user creation cannot be canceled. (Creating a non-managed
311 // profile shouldn't take significant time, and it can easily be deleted
313 if (!new_profile->IsManaged())
316 if (user_initiated) {
317 UMA_HISTOGRAM_MEDIUM_TIMES(
318 "Profile.CreateTimeCanceledNoTimeout",
319 base::TimeTicks::Now() - profile_creation_start_time_);
320 RecordProfileCreationMetrics(Profile::CREATE_STATUS_CANCELED);
323 DCHECK(managed_user_registration_utility_.get());
324 managed_user_registration_utility_.reset();
326 DCHECK_NE(NO_CREATION_IN_PROGRESS, profile_creation_type_);
327 profile_creation_type_ = NO_CREATION_IN_PROGRESS;
329 // Cancelling registration means the callback passed into
330 // RegisterAndInitSync() won't be called, so the cleanup must be done here.
331 profile_path_being_created_.clear();
332 helper::DeleteProfileAtPath(new_profile->GetPath(), web_ui());
335 void CreateProfileHandler::RecordProfileCreationMetrics(
336 Profile::CreateStatus status) {
337 UMA_HISTOGRAM_ENUMERATION("Profile.CreateResult",
339 Profile::MAX_CREATE_STATUS);
340 UMA_HISTOGRAM_MEDIUM_TIMES(
341 "Profile.CreateTimeNoTimeout",
342 base::TimeTicks::Now() - profile_creation_start_time_);
345 void CreateProfileHandler::RecordSupervisedProfileCreationMetrics(
346 GoogleServiceAuthError::State error_state) {
347 if (profile_creation_type_ == SUPERVISED_PROFILE_CREATION) {
348 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileCreateError",
350 GoogleServiceAuthError::NUM_STATES);
351 UMA_HISTOGRAM_MEDIUM_TIMES(
352 "Profile.SupervisedProfileTotalCreateTime",
353 base::TimeTicks::Now() - profile_creation_start_time_);
355 DCHECK_EQ(SUPERVISED_PROFILE_IMPORT, profile_creation_type_);
356 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileImportError",
358 GoogleServiceAuthError::NUM_STATES);
359 UMA_HISTOGRAM_MEDIUM_TIMES(
360 "Profile.SupervisedProfileTotalImportTime",
361 base::TimeTicks::Now() - profile_creation_start_time_);
365 base::string16 CreateProfileHandler::GetProfileCreationErrorMessage(
366 ProfileCreationErrorType error) const {
371 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
372 IDS_MANAGED_USER_IMPORT_SIGN_IN_ERROR :
373 IDS_PROFILES_CREATE_SIGN_IN_ERROR;
377 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
378 IDS_MANAGED_USER_IMPORT_REMOTE_ERROR :
379 IDS_PROFILES_CREATE_REMOTE_ERROR;
383 profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
384 IDS_MANAGED_USER_IMPORT_LOCAL_ERROR :
385 IDS_PROFILES_CREATE_LOCAL_ERROR;
389 return l10n_util::GetStringUTF16(message_id);
392 std::string CreateProfileHandler::GetJavascriptMethodName(
393 ProfileCreationStatus status) const {
395 case PROFILE_CREATION_SUCCESS:
396 return profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
397 "BrowserOptions.showManagedUserImportSuccess" :
398 "BrowserOptions.showCreateProfileSuccess";
399 case PROFILE_CREATION_ERROR:
400 return profile_creation_type_ == SUPERVISED_PROFILE_IMPORT ?
401 "BrowserOptions.showManagedUserImportError" :
402 "BrowserOptions.showCreateProfileError";
406 return std::string();
409 bool CreateProfileHandler::IsValidExistingManagedUserId(
410 const std::string& existing_managed_user_id) const {
411 if (existing_managed_user_id.empty())
414 Profile* profile = Profile::FromWebUI(web_ui());
415 const base::DictionaryValue* dict =
416 ManagedUserSyncServiceFactory::GetForProfile(profile)->GetManagedUsers();
417 if (!dict->HasKey(existing_managed_user_id))
420 // Check if this managed user already exists on this machine.
421 const ProfileInfoCache& cache =
422 g_browser_process->profile_manager()->GetProfileInfoCache();
423 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
424 if (existing_managed_user_id == cache.GetManagedUserIdOfProfileAtIndex(i))
430 } // namespace options