1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// found in the LICENSE file.
4513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
5513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/background_application_list_model.h"
6513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
7513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include <algorithm>
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <set>
9513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
10513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/stl_util-inl.h"
11513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/utf_string_conversions.h"
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/app/chrome_command_ids.h"
13513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/background_mode_manager.h"
14513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/browser_process.h"
15513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/extensions/extension_prefs.h"
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
17513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/extensions/image_loading_tracker.h"
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
19513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/common/extensions/extension.h"
20513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/common/extensions/extension_resource.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util_collator.h"
24513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
25513209b27ff55e2841eac0e4120199c23acce758Ben Murdochclass ExtensionNameComparator {
26513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch public:
27513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  explicit ExtensionNameComparator(icu::Collator* collator);
28513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool operator()(const Extension* x, const Extension* y);
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
30513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch private:
31513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  icu::Collator* collator_;
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
34513209b27ff55e2841eac0e4120199c23acce758Ben MurdochExtensionNameComparator::ExtensionNameComparator(icu::Collator* collator)
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  : collator_(collator) {
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ExtensionNameComparator::operator()(const Extension* x,
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                         const Extension* y) {
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return l10n_util::StringComparator<string16>(collator_)(
41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    UTF8ToUTF16(x->name()),
42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    UTF8ToUTF16(y->name()));
43513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Background application representation, private to the
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// BackgroundApplicationListModel class.
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdochclass BackgroundApplicationListModel::Application
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  : public ImageLoadingTracker::Observer {
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch public:
50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Application(BackgroundApplicationListModel* model,
51513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              const Extension* an_extension);
52513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual ~Application();
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
55513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Invoked when a request icon is available.
56513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual void OnImageLoaded(SkBitmap* image,
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             const ExtensionResource& resource,
58513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             int index);
59513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Uses the FILE thread to request this extension's icon, sized
61513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // appropriately.
62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  void RequestIcon(Extension::Icons size);
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension_;
65513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_ptr<SkBitmap> icon_;
66513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  BackgroundApplicationListModel* model_;
67513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ImageLoadingTracker tracker_;
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
69513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
70513209b27ff55e2841eac0e4120199c23acce758Ben Murdochnamespace {
7121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid GetServiceApplications(ExtensionService* service,
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                            ExtensionList* applications_result) {
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const ExtensionList* extensions = service->extensions();
74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (ExtensionList::const_iterator cursor = extensions->begin();
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       cursor != extensions->end();
77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       ++cursor) {
78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension = *cursor;
79513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (BackgroundApplicationListModel::IsBackgroundApp(*extension))
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      applications_result->push_back(extension);
81513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string locale = g_browser_process->GetApplicationLocale();
83513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  icu::Locale loc(locale.c_str());
84513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UErrorCode error = U_ZERO_ERROR;
85513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(loc, error));
86513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sort(applications_result->begin(), applications_result->end(),
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       ExtensionNameComparator(collator.get()));
88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
90513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool HasBackgroundAppPermission(
91513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::set<std::string>& api_permissions) {
92513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return Extension::HasApiPermission(
93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      api_permissions, Extension::kBackgroundPermission);
94513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace
96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
97513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid
98513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::Observer::OnApplicationDataChanged(
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
101513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
102513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid
103513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::Observer::OnApplicationListChanged() {
104513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
105513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
106513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::Observer::~Observer() {
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
109513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::Application::~Application() {
110513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
111513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
112513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::Application::Application(
113513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    BackgroundApplicationListModel* model,
114513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension)
115513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : extension_(extension),
116513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      icon_(NULL),
117513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      model_(model),
118513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
119513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
121513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::Application::OnImageLoaded(
122513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    SkBitmap* image,
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ExtensionResource& resource,
124513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    int index) {
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!image)
126513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
127513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  icon_.reset(new SkBitmap(*image));
128513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  model_->OnApplicationDataChanged(extension_);
129513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
130513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
131513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::Application::RequestIcon(
132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    Extension::Icons size) {
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionResource resource = extension_->GetIconResource(
134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      size, ExtensionIconSet::MATCH_BIGGER);
135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  tracker_.LoadImage(extension_, resource, gfx::Size(size, size),
136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                     ImageLoadingTracker::CACHE);
137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
139513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::~BackgroundApplicationListModel() {
140513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  STLDeleteContainerPairSecondPointers(applications_.begin(),
141513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                       applications_.end());
142513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
143513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
144513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::BackgroundApplicationListModel(Profile* profile)
145513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : profile_(profile) {
146513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(profile_);
147513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  registrar_.Add(this,
148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 NotificationType::EXTENSION_LOADED,
149513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 Source<Profile>(profile));
150513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  registrar_.Add(this,
151513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 NotificationType::EXTENSION_UNLOADED,
152513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 Source<Profile>(profile));
153513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  registrar_.Add(this,
154513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 NotificationType::EXTENSIONS_READY,
155513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 Source<Profile>(profile));
15621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile->GetExtensionService();
15721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (service && service->is_ready())
15821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    Update();
159513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
160513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
161513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::AddObserver(Observer* observer) {
162513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  observers_.AddObserver(observer);
163513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
164513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
165513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::AssociateApplicationData(
166513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
167513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(IsBackgroundApp(*extension));
168513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Application* application = FindApplication(extension);
169513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!application) {
17021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // App position is used as a dynamic command and so must be less than any
17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // predefined command id.
17221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (applications_.size() >= IDC_MinimumLabelValue) {
17321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      LOG(ERROR) << "Background application limit of " << IDC_MinimumLabelValue
17421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                 << " exceeded.  Ignoring.";
17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return;
17621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
177513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    application = new Application(this, extension);
178513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    applications_[extension->id()] = application;
179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    application->RequestIcon(Extension::EXTENSION_ICON_BITTY);
180513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
182513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
183513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::DissociateApplicationData(
184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
185513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ApplicationMap::iterator found = applications_.find(extension->id());
186513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (found != applications_.end()) {
187513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    delete found->second;
188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    applications_.erase(found);
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
191513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
192513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst Extension* BackgroundApplicationListModel::GetExtension(
193513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    int position) const {
194513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(position >= 0 && static_cast<size_t>(position) < extensions_.size());
195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return extensions_[position];
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
198513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst BackgroundApplicationListModel::Application*
199513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::FindApplication(
200513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) const {
201513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const std::string& id = extension->id();
202513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ApplicationMap::const_iterator found = applications_.find(id);
203513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return (found == applications_.end()) ? NULL : found->second;
204513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
205513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
206513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::Application*
207513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBackgroundApplicationListModel::FindApplication(const Extension* extension) {
208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const std::string& id = extension->id();
209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ApplicationMap::iterator found = applications_.find(id);
210513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return (found == applications_.end()) ? NULL : found->second;
211513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
212513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
213513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst SkBitmap* BackgroundApplicationListModel::GetIcon(
214513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
215513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Application* application = FindApplication(extension);
216513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (application)
217513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return application->icon_.get();
218513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  AssociateApplicationData(extension);
219513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return NULL;
220513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
221513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
222513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint BackgroundApplicationListModel::GetPosition(
223513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) const {
224513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int position = 0;
225513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const std::string& id = extension->id();
226513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (ExtensionList::const_iterator cursor = extensions_.begin();
227513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       cursor != extensions_.end();
228513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       ++cursor, ++position) {
229513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (id == cursor->get()->id())
230513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return position;
231513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
232513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NOTREACHED();
233513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return -1;
234513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
235513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
236513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
237513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool BackgroundApplicationListModel::IsBackgroundApp(
238513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension& extension) {
239513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return HasBackgroundAppPermission(extension.api_permissions());
240513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
241513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
242513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::Observe(
243513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    NotificationType type,
244513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const NotificationSource& source,
245513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const NotificationDetails& details) {
246513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (type == NotificationType::EXTENSIONS_READY) {
247513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    Update();
248513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
249513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
25021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile_->GetExtensionService();
251513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!service || !service->is_ready())
252513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
253201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
254513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  switch (type.value) {
255513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case NotificationType::EXTENSION_LOADED:
256513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      OnExtensionLoaded(Details<Extension>(details).ptr());
257513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
258513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case NotificationType::EXTENSION_UNLOADED:
25921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      OnExtensionUnloaded(Details<UnloadedExtensionInfo>(details)->extension);
260513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
261513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    default:
262513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NOTREACHED() << "Received unexpected notification";
263513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
264513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
265513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
266513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::OnApplicationDataChanged(
267513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
268513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  FOR_EACH_OBSERVER(Observer, observers_, OnApplicationDataChanged(extension));
269513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
270513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
271513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::OnExtensionLoaded(Extension* extension) {
272513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // We only care about extensions that are background applications
273513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!IsBackgroundApp(*extension))
274513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
275513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  AssociateApplicationData(extension);
276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Update();
277513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
278513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
27921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid BackgroundApplicationListModel::OnExtensionUnloaded(
28021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const Extension* extension) {
281513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!IsBackgroundApp(*extension))
282513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
283513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Update();
284513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DissociateApplicationData(extension);
285513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
286513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
287513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::RemoveObserver(Observer* observer) {
288513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  observers_.RemoveObserver(observer);
289513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
290513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
291513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Update queries the extensions service of the profile with which the model was
292513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// initialized to determine the current set of background applications.  If that
293513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// differs from the old list, it generates OnApplicationListChanged events for
294513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// each observer.
295513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundApplicationListModel::Update() {
29621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile_->GetExtensionService();
297513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
298513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Discover current background applications, compare with previous list, which
299513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // is consistently sorted, and notify observers if they differ.
300513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionList extensions;
301513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GetServiceApplications(service, &extensions);
302513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionList::const_iterator old_cursor = extensions_.begin();
303513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionList::const_iterator new_cursor = extensions.begin();
304513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  while (old_cursor != extensions_.end() &&
305513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch         new_cursor != extensions.end() &&
306513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch         (*old_cursor)->name() == (*new_cursor)->name() &&
307513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch         (*old_cursor)->id() == (*new_cursor)->id()) {
308513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ++old_cursor;
309513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ++new_cursor;
310513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
311513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (old_cursor != extensions_.end() || new_cursor != extensions.end()) {
312513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    extensions_ = extensions;
313513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    FOR_EACH_OBSERVER(Observer, observers_, OnApplicationListChanged());
314513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
315513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
316