1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// found in the LICENSE file.
4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/bind.h"
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/callback.h"
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/stringprintf.h"
12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/values.h"
13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/profiles/profile_avatar_icon_util.h"
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/common/pref_names.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "sync/api/sync_change.h"
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "sync/api/sync_data.h"
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "sync/api/sync_error.h"
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "sync/api/sync_error_factory.h"
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "sync/api/sync_merge_result.h"
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "sync/protocol/sync.pb.h"
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/user_manager/user_image/default_user_images.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using base::DictionaryValue;
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using user_prefs::PrefRegistrySyncable;
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using syncer::SUPERVISED_USERS;
30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::ModelType;
31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncChange;
32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncChangeList;
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncChangeProcessor;
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncData;
35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncDataList;
36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncError;
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncErrorFactory;
38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using syncer::SyncMergeResult;
39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using sync_pb::ManagedUserSpecifics;
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)namespace {
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(OS_CHROMEOS)
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#else
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)SyncData CreateLocalSyncData(const std::string& id,
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                             const std::string& name,
51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                             bool acknowledged,
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             const std::string& master_key,
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             const std::string& chrome_avatar,
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             const std::string& chromeos_avatar,
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             const std::string& password_signature_key,
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             const std::string& password_encryption_key) {
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ::sync_pb::EntitySpecifics specifics;
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  specifics.mutable_managed_user()->set_id(id);
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  specifics.mutable_managed_user()->set_name(name);
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!chrome_avatar.empty())
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!chromeos_avatar.empty())
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    specifics.mutable_managed_user()->set_chromeos_avatar(chromeos_avatar);
64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!master_key.empty())
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    specifics.mutable_managed_user()->set_master_key(master_key);
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (acknowledged)
67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    specifics.mutable_managed_user()->set_acknowledged(true);
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!password_signature_key.empty()) {
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    specifics.mutable_managed_user()->
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        set_password_signature_key(password_signature_key);
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!password_encryption_key.empty()) {
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    specifics.mutable_managed_user()->
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        set_password_encryption_key(password_encryption_key);
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return SyncData::CreateLocalData(id, name, specifics);
77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)SyncData CreateSyncDataFromDictionaryEntry(const std::string& id,
8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                           const base::Value& value) {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::DictionaryValue* dict = NULL;
8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  bool success = value.GetAsDictionary(&dict);
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(success);
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool acknowledged = false;
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string name;
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict->GetString(SupervisedUserSyncService::kName, &name);
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!name.empty());
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string master_key;
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string chrome_avatar;
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict->GetString(SupervisedUserSyncService::kChromeAvatar, &chrome_avatar);
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string chromeos_avatar;
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict->GetString(SupervisedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string signature;
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict->GetString(SupervisedUserSyncService::kPasswordSignatureKey, &signature);
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string encryption;
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  &encryption);
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
10123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return CreateLocalSyncData(id,
10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             name,
10323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             acknowledged,
10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             master_key,
10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             chrome_avatar,
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             chromeos_avatar,
10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             signature,
10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             encryption);
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}  // namespace
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char SupervisedUserSyncService::kAcknowledged[] = "acknowledged";
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char SupervisedUserSyncService::kChromeAvatar[] = "chromeAvatar";
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char SupervisedUserSyncService::kChromeOsAvatar[] = "chromeOsAvatar";
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char SupervisedUserSyncService::kMasterKey[] = "masterKey";
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char SupervisedUserSyncService::kName[] = "name";
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char SupervisedUserSyncService::kPasswordSignatureKey[] =
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    "passwordSignatureKey";
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char SupervisedUserSyncService::kPasswordEncryptionKey[] =
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    "passwordEncryptionKey";
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const int SupervisedUserSyncService::kNoAvatar = -100;
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSyncService::SupervisedUserSyncService(PrefService* prefs)
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    : prefs_(prefs) {
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pref_change_registrar_.Init(prefs_);
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  pref_change_registrar_.Add(
128a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      prefs::kGoogleServicesLastUsername,
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      base::Bind(&SupervisedUserSyncService::OnLastSignedInUsernameChange,
130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                 base::Unretained(this)));
131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
132a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSyncService::~SupervisedUserSyncService() {
134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// static
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::RegisterProfilePrefs(
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    PrefRegistrySyncable* registry) {
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  registry->RegisterDictionaryPref(prefs::kSupervisedUsers,
140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                   PrefRegistrySyncable::UNSYNCABLE_PREF);
141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// static
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SupervisedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                               int* avatar_index) {
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(avatar_index);
14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (avatar_str.empty()) {
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    *avatar_index = kNoAvatar;
14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return true;
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
1518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(OS_CHROMEOS)
1528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const char* prefix = kChromeOSAvatarPrefix;
1538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#else
1548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const char* prefix = kChromeAvatarPrefix;
1558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
1568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  size_t prefix_len = strlen(prefix);
15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (avatar_str.size() <= prefix_len ||
1588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      avatar_str.substr(0, prefix_len) != prefix) {
15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::StringToInt(avatar_str.substr(prefix_len), avatar_index))
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int kChromeOSDummyAvatarIndex = -111;
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (*avatar_index == kChromeOSDummyAvatarIndex ||
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          (*avatar_index >= user_manager::kFirstDefaultImageIndex &&
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           *avatar_index < user_manager::kDefaultImagesCount));
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check if the Chrome avatar index is set to a dummy value. Some early
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // supervised user profiles on ChromeOS stored a dummy avatar index as a
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Chrome Avatar before there was logic to sync the ChromeOS avatar
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // separately. Handle this as if the Chrome Avatar was not chosen yet (which
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // is correct for these profiles).
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (*avatar_index == kChromeOSDummyAvatarIndex)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *avatar_index = kNoAvatar;
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (*avatar_index == kNoAvatar ||
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          (*avatar_index >= 0 &&
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           static_cast<size_t>(*avatar_index) <
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               profiles::GetDefaultAvatarIconCount()));
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
18658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// static
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)std::string SupervisedUserSyncService::BuildAvatarString(int avatar_index) {
1888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(OS_CHROMEOS)
1898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const char* prefix = kChromeOSAvatarPrefix;
1908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#else
1918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const char* prefix = kChromeAvatarPrefix;
1928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
1938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return base::StringPrintf("%s%d", prefix, avatar_index);
19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
19558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::AddObserver(
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SupervisedUserSyncServiceObserver* observer) {
198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  observers_.AddObserver(observer);
199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
200a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::RemoveObserver(
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SupervisedUserSyncServiceObserver* observer) {
203a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  observers_.RemoveObserver(observer);
204a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
205a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<base::DictionaryValue> SupervisedUserSyncService::CreateDictionary(
20723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& name,
20823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& master_key,
20923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& signature_key,
21023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& encryption_key,
21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int avatar_index) {
21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result->SetString(kName, name);
21423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result->SetString(kMasterKey, master_key);
21523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result->SetString(kPasswordSignatureKey, signature_key);
21623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result->SetString(kPasswordEncryptionKey, encryption_key);
21723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // TODO(akuegel): Get rid of the avatar stuff here when Chrome OS switches
21823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // to the avatar index that is stored as a shared setting.
21923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::string chrome_avatar;
22023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::string chromeos_avatar;
22123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#if defined(OS_CHROMEOS)
22223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  chromeos_avatar = BuildAvatarString(avatar_index);
22323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#else
22423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  chrome_avatar = BuildAvatarString(avatar_index);
22523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#endif
22623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result->SetString(kChromeAvatar, chrome_avatar);
22723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  result->SetString(kChromeOsAvatar, chromeos_avatar);
22823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return result.Pass();
22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
23023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::AddSupervisedUser(
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& id,
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& name,
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& master_key,
235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& signature_key,
236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& encryption_key,
237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    int avatar_index) {
238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  UpdateSupervisedUserImpl(id,
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           name,
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           master_key,
241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           signature_key,
242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           encryption_key,
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           avatar_index,
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           true /* add */);
24523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
24623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::UpdateSupervisedUser(
24823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& id,
24923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& name,
25023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& master_key,
25123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& signature_key,
25223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& encryption_key,
25323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int avatar_index) {
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  UpdateSupervisedUserImpl(id,
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           name,
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           master_key,
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           signature_key,
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           encryption_key,
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           avatar_index,
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           false /* update */);
26123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
26223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::UpdateSupervisedUserImpl(
26423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& id,
26523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& name,
26623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& master_key,
26723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& signature_key,
26823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& encryption_key,
26923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int avatar_index,
27023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    bool add_user) {
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = update.Get();
27323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> value = CreateDictionary(
27423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      name, master_key, signature_key, encryption_key, avatar_index);
27523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
27623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(add_user, !dict->HasKey(id));
27723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  base::DictionaryValue* entry = value.get();
27823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  dict->SetWithoutPathExpansion(id, value.release());
279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!sync_processor_)
281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
283a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // If we're already syncing, create a new change and upload it.
284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncChangeList change_list;
28523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  change_list.push_back(
28623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      SyncChange(FROM_HERE,
28723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                 add_user ? SyncChange::ACTION_ADD : SyncChange::ACTION_UPDATE,
28823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                 CreateSyncDataFromDictionaryEntry(id, *entry)));
289a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncError error =
290a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
291a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(!error.IsSet()) << error.ToString();
292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
293a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::DeleteSupervisedUser(const std::string& id) {
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
296d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool success = update->RemoveWithoutPathExpansion(id, NULL);
297d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(success);
298d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
299a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!sync_processor_)
300a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
301a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
302a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncChangeList change_list;
303a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  change_list.push_back(SyncChange(
304a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      FROM_HERE,
305a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncChange::ACTION_DELETE,
306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      SyncData::CreateLocalDelete(id, SUPERVISED_USERS)));
307a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncError sync_error =
308a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
309a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(!sync_error.IsSet());
310a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
311a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const base::DictionaryValue* SupervisedUserSyncService::GetSupervisedUsers() {
31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(sync_processor_);
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return prefs_->GetDictionary(prefs::kSupervisedUsers);
31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
31658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SupervisedUserSyncService::UpdateSupervisedUserAvatarIfNeeded(
318d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& id,
319d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int avatar_index) {
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = update.Get();
322d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(dict->HasKey(id));
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* value = NULL;
324d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool success = dict->GetDictionaryWithoutPathExpansion(id, &value);
325d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(success);
326d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool acknowledged = false;
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  value->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string name;
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  value->GetString(SupervisedUserSyncService::kName, &name);
331d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string master_key;
332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  value->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string signature;
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  value->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   &signature);
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string encryption;
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  value->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   &encryption);
339d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string chromeos_avatar;
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  value->GetString(SupervisedUserSyncService::kChromeOsAvatar,
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   &chromeos_avatar);
342d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string chrome_avatar;
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  value->GetString(SupervisedUserSyncService::kChromeAvatar, &chrome_avatar);
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The following check is just for safety. We want to avoid that the existing
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // avatar selection is overwritten. Currently we don't allow the user to
346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // choose a different avatar in the recreation dialog, anyway, if there is
347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // already an avatar selected.
348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(OS_CHROMEOS)
349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!chromeos_avatar.empty() && avatar_index != kNoAvatar)
350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return false;
351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#else
352d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
353d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return false;
354a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
355d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
356d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  chrome_avatar = avatar_index == kNoAvatar ?
357d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      std::string() : BuildAvatarString(avatar_index);
358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(OS_CHROMEOS)
359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  value->SetString(kChromeOsAvatar, chrome_avatar);
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#else
361d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  value->SetString(kChromeAvatar, chrome_avatar);
362a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
363d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
364d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!sync_processor_)
365d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return true;
366d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
367d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SyncChangeList change_list;
368d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  change_list.push_back(SyncChange(
369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      FROM_HERE,
370d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      SyncChange::ACTION_UPDATE,
371d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      CreateLocalSyncData(id, name, acknowledged, master_key,
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                          chrome_avatar, chromeos_avatar,
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                          signature, encryption)));
374d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SyncError error =
375d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
376d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(!error.IsSet()) << error.ToString();
377d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return true;
378d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::ClearSupervisedUserAvatar(
381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& id) {
382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool cleared = UpdateSupervisedUserAvatarIfNeeded(id, kNoAvatar);
383d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(cleared);
384d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
385d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::GetSupervisedUsersAsync(
387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const SupervisedUsersCallback& callback) {
38858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If we are already syncing, just run the callback.
38958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (sync_processor_) {
390f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    callback.Run(GetSupervisedUsers());
39158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
39258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
39358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
39458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Otherwise queue it up until we start syncing.
39558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  callbacks_.push_back(callback);
39658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
39758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
398f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::Shutdown() {
399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NotifySupervisedUsersSyncingStopped();
400a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
401a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
402f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncMergeResult SupervisedUserSyncService::MergeDataAndStartSyncing(
403a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ModelType type,
404a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const SyncDataList& initial_sync_data,
405a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    scoped_ptr<SyncChangeProcessor> sync_processor,
406a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    scoped_ptr<SyncErrorFactory> error_handler) {
407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(SUPERVISED_USERS, type);
408a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  sync_processor_ = sync_processor.Pass();
409a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  error_handler_ = error_handler.Pass();
410a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
411a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncChangeList change_list;
412f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SyncMergeResult result(SUPERVISED_USERS);
413a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = update.Get();
416a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  result.set_num_items_before_association(dict->size());
417a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::set<std::string> seen_ids;
418a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int num_items_added = 0;
419a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int num_items_modified = 0;
420a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (SyncDataList::const_iterator it = initial_sync_data.begin();
421a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       it != initial_sync_data.end(); ++it) {
422f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK_EQ(SUPERVISED_USERS, it->GetDataType());
423f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ManagedUserSpecifics& supervised_user =
424a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        it->GetSpecifics().managed_user();
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* value = new base::DictionaryValue();
426f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    value->SetString(kName, supervised_user.name());
427f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    value->SetBoolean(kAcknowledged, supervised_user.acknowledged());
428f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    value->SetString(kMasterKey, supervised_user.master_key());
429f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    value->SetString(kChromeAvatar, supervised_user.chrome_avatar());
430f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    value->SetString(kChromeOsAvatar, supervised_user.chromeos_avatar());
431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    value->SetString(kPasswordSignatureKey,
432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     supervised_user.password_signature_key());
433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    value->SetString(kPasswordEncryptionKey,
434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     supervised_user.password_encryption_key());
435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (dict->HasKey(supervised_user.id()))
436a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      num_items_modified++;
437a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    else
438a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      num_items_added++;
439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    dict->SetWithoutPathExpansion(supervised_user.id(), value);
440f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    seen_ids.insert(supervised_user.id());
441a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
442a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
444a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (seen_ids.find(it.key()) != seen_ids.end())
445a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue;
446a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
44723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    change_list.push_back(
44823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        SyncChange(FROM_HERE,
44923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                   SyncChange::ACTION_ADD,
45023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                   CreateSyncDataFromDictionaryEntry(it.key(), it.value())));
451a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
452a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
453a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
454a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  result.set_num_items_modified(num_items_modified);
455a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  result.set_num_items_added(num_items_added);
456a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  result.set_num_items_after_association(dict->size());
457a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
45858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DispatchCallbacks();
45958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
460a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return result;
461a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
462a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
463f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::StopSyncing(ModelType type) {
464f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(SUPERVISED_USERS, type);
465a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // The observers may want to change the Sync data, so notify them before
466a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // resetting the |sync_processor_|.
467f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  NotifySupervisedUsersSyncingStopped();
468a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  sync_processor_.reset();
469a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  error_handler_.reset();
470a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
471a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
472f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncDataList SupervisedUserSyncService::GetAllSyncData(
473a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ModelType type) const {
474a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncDataList data;
475f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = update.Get();
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance())
47823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    data.push_back(CreateSyncDataFromDictionaryEntry(it.key(), it.value()));
47958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
480a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return data;
481a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
482a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
483f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncError SupervisedUserSyncService::ProcessSyncChanges(
484a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const tracked_objects::Location& from_here,
485a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const SyncChangeList& change_list) {
486a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncError error;
487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = update.Get();
489a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (SyncChangeList::const_iterator it = change_list.begin();
490a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       it != change_list.end(); ++it) {
491a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    SyncData data = it->sync_data();
492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK_EQ(SUPERVISED_USERS, data.GetDataType());
493f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ManagedUserSpecifics& supervised_user =
494a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        data.GetSpecifics().managed_user();
495a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    switch (it->change_type()) {
496a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      case SyncChange::ACTION_ADD:
497a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      case SyncChange::ACTION_UPDATE: {
498a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        // Every item we get from the server should be acknowledged.
499f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        DCHECK(supervised_user.acknowledged());
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        const base::DictionaryValue* old_value = NULL;
501f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        dict->GetDictionaryWithoutPathExpansion(supervised_user.id(),
502f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                &old_value);
503a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
504f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        // For an update action, the supervised user should already exist, for
505f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        // an add action, it should not.
506a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        DCHECK_EQ(
507a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
508a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            it->change_type());
509a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
510f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        // If the supervised user switched from unacknowledged to acknowledged,
511a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        // we might need to continue with a registration.
512a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        if (old_value && !old_value->HasKey(kAcknowledged))
513f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          NotifySupervisedUserAcknowledged(supervised_user.id());
514a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::DictionaryValue* value = new base::DictionaryValue;
516f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        value->SetString(kName, supervised_user.name());
517f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        value->SetBoolean(kAcknowledged, supervised_user.acknowledged());
518f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        value->SetString(kMasterKey, supervised_user.master_key());
519f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        value->SetString(kChromeAvatar, supervised_user.chrome_avatar());
520f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        value->SetString(kChromeOsAvatar, supervised_user.chromeos_avatar());
521a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        value->SetString(kPasswordSignatureKey,
522f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         supervised_user.password_signature_key());
523a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        value->SetString(kPasswordEncryptionKey,
524f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         supervised_user.password_encryption_key());
525f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        dict->SetWithoutPathExpansion(supervised_user.id(), value);
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
527f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        NotifySupervisedUsersChanged();
528a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        break;
529a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      }
530a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      case SyncChange::ACTION_DELETE: {
531f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        DCHECK(dict->HasKey(supervised_user.id())) << supervised_user.id();
532f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        dict->RemoveWithoutPathExpansion(supervised_user.id(), NULL);
533a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        break;
534a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      }
535a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      case SyncChange::ACTION_INVALID: {
536a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        NOTREACHED();
537a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        break;
538a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      }
539a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
540a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
541a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return error;
542a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
543a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
544f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::OnLastSignedInUsernameChange() {
545a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(!sync_processor_);
546a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
547f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // If the last signed in user changes, we clear all data, to avoid supervised
548a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // users from one custodian appearing in another one's profile.
549f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  prefs_->ClearPref(prefs::kSupervisedUsers);
550a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
551a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
552f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::NotifySupervisedUserAcknowledged(
553f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& supervised_user_id) {
554f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
555f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    OnSupervisedUserAcknowledged(supervised_user_id));
556a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
557a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
558f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::NotifySupervisedUsersSyncingStopped() {
559f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
560f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    OnSupervisedUsersSyncingStopped());
561a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
56258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
563f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::NotifySupervisedUsersChanged() {
564f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver,
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    observers_,
566f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    OnSupervisedUsersChanged());
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
569f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSyncService::DispatchCallbacks() {
570f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const base::DictionaryValue* supervised_users =
571f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      prefs_->GetDictionary(prefs::kSupervisedUsers);
572f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (std::vector<SupervisedUsersCallback>::iterator it = callbacks_.begin();
57358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       it != callbacks_.end(); ++it) {
574f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    it->Run(supervised_users);
57558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
57658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  callbacks_.clear();
57758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
578