sync_app_helper.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync/test/integration/sync_app_helper.h"
6
7#include "chrome/browser/extensions/extension_service.h"
8#include "chrome/browser/extensions/launch_util.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/sync/test/integration/extensions_helper.h"
11#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
12#include "chrome/browser/sync/test/integration/sync_extension_helper.h"
13#include "chrome/common/extensions/extension_constants.h"
14#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
15#include "chrome/common/extensions/sync_helper.h"
16#include "components/crx_file/id_util.h"
17#include "extensions/browser/app_sorting.h"
18#include "extensions/browser/extension_prefs.h"
19#include "extensions/browser/extension_registry.h"
20#include "extensions/browser/extension_system.h"
21#include "extensions/common/extension_set.h"
22
23using extensions::ExtensionPrefs;
24
25namespace {
26
27struct AppState {
28  AppState();
29  ~AppState();
30  bool IsValid() const;
31  bool Equals(const AppState& other) const;
32
33  syncer::StringOrdinal app_launch_ordinal;
34  syncer::StringOrdinal page_ordinal;
35  extensions::LaunchType launch_type;
36  GURL launch_web_url;
37  std::string description;
38  std::string name;
39  bool from_bookmark;
40};
41
42typedef std::map<std::string, AppState> AppStateMap;
43
44AppState::AppState() : launch_type(extensions::LAUNCH_TYPE_INVALID) {}
45
46AppState::~AppState() {}
47
48bool AppState::IsValid() const {
49  return page_ordinal.IsValid() && app_launch_ordinal.IsValid();
50}
51
52bool AppState::Equals(const AppState& other) const {
53  return app_launch_ordinal.Equals(other.app_launch_ordinal) &&
54         page_ordinal.Equals(other.page_ordinal) &&
55         launch_type == other.launch_type &&
56         launch_web_url == other.launch_web_url &&
57         description == other.description && name == other.name &&
58         from_bookmark == other.from_bookmark;
59}
60
61// Load all the app specific values for |id| into |app_state|.
62void LoadApp(content::BrowserContext* context,
63             const std::string& id,
64             AppState* app_state) {
65  ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
66  app_state->app_launch_ordinal = prefs->app_sorting()->GetAppLaunchOrdinal(id);
67  app_state->page_ordinal = prefs->app_sorting()->GetPageOrdinal(id);
68  app_state->launch_type = extensions::GetLaunchTypePrefValue(prefs, id);
69  ExtensionService* service =
70      extensions::ExtensionSystem::Get(context)->extension_service();
71  const extensions::Extension* extension = service->GetInstalledExtension(id);
72  app_state->launch_web_url =
73      extensions::AppLaunchInfo::GetLaunchWebURL(extension);
74  app_state->description = extension->description();
75  app_state->name = extension->name();
76  app_state->from_bookmark = extension->from_bookmark();
77}
78
79// Returns a map from |profile|'s installed extensions to their state.
80AppStateMap GetAppStates(Profile* profile) {
81  AppStateMap app_state_map;
82
83  scoped_ptr<const extensions::ExtensionSet> extensions(
84      extensions::ExtensionRegistry::Get(profile)
85          ->GenerateInstalledExtensionsSet());
86  for (extensions::ExtensionSet::const_iterator it = extensions->begin();
87       it != extensions->end(); ++it) {
88    if (extensions::sync_helper::IsSyncableApp(it->get())) {
89      const std::string& id = (*it)->id();
90      LoadApp(profile, id, &(app_state_map[id]));
91    }
92  }
93
94  const extensions::PendingExtensionManager* pending_extension_manager =
95      extensions::ExtensionSystem::Get(profile)
96          ->extension_service()
97          ->pending_extension_manager();
98
99  std::list<std::string> pending_crx_ids;
100  pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);
101
102  for (std::list<std::string>::const_iterator id = pending_crx_ids.begin();
103       id != pending_crx_ids.end(); ++id) {
104    LoadApp(profile, *id, &(app_state_map[*id]));
105  }
106
107  return app_state_map;
108}
109
110}  // namespace
111
112SyncAppHelper* SyncAppHelper::GetInstance() {
113  SyncAppHelper* instance = Singleton<SyncAppHelper>::get();
114  instance->SetupIfNecessary(sync_datatype_helper::test());
115  return instance;
116}
117
118void SyncAppHelper::SetupIfNecessary(SyncTest* test) {
119  if (setup_completed_)
120    return;
121
122  for (int i = 0; i < test->num_clients(); ++i) {
123    extensions::ExtensionSystem::Get(
124        test->GetProfile(i))->InitForRegularProfile(true);
125  }
126  extensions::ExtensionSystem::Get(
127      test->verifier())->InitForRegularProfile(true);
128
129  setup_completed_ = true;
130}
131
132bool SyncAppHelper::AppStatesMatch(Profile* profile1, Profile* profile2) {
133  if (!SyncExtensionHelper::GetInstance()->ExtensionStatesMatch(
134          profile1, profile2))
135    return false;
136
137  const AppStateMap& state_map1 = GetAppStates(profile1);
138  const AppStateMap& state_map2 = GetAppStates(profile2);
139  if (state_map1.size() != state_map2.size()) {
140    DVLOG(2) << "Number of Apps for profile " << profile1->GetDebugName()
141             << " does not match profile " << profile2->GetDebugName();
142    return false;
143  }
144
145  AppStateMap::const_iterator it1 = state_map1.begin();
146  AppStateMap::const_iterator it2 = state_map2.begin();
147  while (it1 != state_map1.end()) {
148    if (it1->first != it2->first) {
149      DVLOG(2) << "Apps for profile " << profile1->GetDebugName()
150               << " do not match profile " << profile2->GetDebugName();
151      return false;
152    } else if (!it1->second.IsValid()) {
153      DVLOG(2) << "Apps for profile " << profile1->GetDebugName()
154               << " are not valid.";
155      return false;
156    } else if (!it2->second.IsValid()) {
157      DVLOG(2) << "Apps for profile " << profile2->GetDebugName()
158               << " are not valid.";
159      return false;
160    } else if (!it1->second.Equals(it2->second)) {
161      DVLOG(2) << "App states for profile " << profile1->GetDebugName()
162               << " do not match profile " << profile2->GetDebugName();
163      return false;
164    }
165    ++it1;
166    ++it2;
167  }
168
169  return true;
170}
171
172syncer::StringOrdinal SyncAppHelper::GetPageOrdinalForApp(
173    Profile* profile,
174    const std::string& name) {
175  return ExtensionPrefs::Get(profile)->app_sorting()->GetPageOrdinal(
176      crx_file::id_util::GenerateId(name));
177}
178
179void SyncAppHelper::SetPageOrdinalForApp(
180    Profile* profile,
181    const std::string& name,
182    const syncer::StringOrdinal& page_ordinal) {
183  ExtensionPrefs::Get(profile)->app_sorting()->SetPageOrdinal(
184      crx_file::id_util::GenerateId(name), page_ordinal);
185}
186
187syncer::StringOrdinal SyncAppHelper::GetAppLaunchOrdinalForApp(
188    Profile* profile,
189    const std::string& name) {
190  return ExtensionPrefs::Get(profile)->app_sorting()->GetAppLaunchOrdinal(
191      crx_file::id_util::GenerateId(name));
192}
193
194void SyncAppHelper::SetAppLaunchOrdinalForApp(
195    Profile* profile,
196    const std::string& name,
197    const syncer::StringOrdinal& app_launch_ordinal) {
198  ExtensionPrefs::Get(profile)->app_sorting()->SetAppLaunchOrdinal(
199      crx_file::id_util::GenerateId(name), app_launch_ordinal);
200}
201
202void SyncAppHelper::FixNTPOrdinalCollisions(Profile* profile) {
203  ExtensionPrefs::Get(profile)->app_sorting()->FixNTPOrdinalCollisions();
204}
205
206SyncAppHelper::SyncAppHelper() : setup_completed_(false) {}
207
208SyncAppHelper::~SyncAppHelper() {}
209