15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/background/background_application_list_model.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/sha1.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/background/background_contents_service.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/background/background_contents_service_factory.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/background/background_mode_manager.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/extension_util.h"
296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/image_loader.h"
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/notification_types.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension_icon_set.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/extension_resource.h"
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest_handlers/background_info.h"
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h"
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/common/permissions/permission_set.h"
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util_collator.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::APIPermission;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::ExtensionList;
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using extensions::ExtensionRegistry;
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using extensions::ExtensionSet;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::PermissionSet;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::UnloadedExtensionInfo;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::UpdatedExtensionPermissionsInfo;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ExtensionNameComparator {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit ExtensionNameComparator(icu::Collator* collator);
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool operator()(const scoped_refptr<const Extension>& x,
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  const scoped_refptr<const Extension>& y);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::Collator* collator_;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionNameComparator::ExtensionNameComparator(icu::Collator* collator)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : collator_(collator) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ExtensionNameComparator::operator()(
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const scoped_refptr<const Extension>& x,
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const scoped_refptr<const Extension>& y) {
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return l10n_util::StringComparator<base::string16>(collator_)(
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF8ToUTF16(x->name()), base::UTF8ToUTF16(y->name()));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Background application representation, private to the
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundApplicationListModel class.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BackgroundApplicationListModel::Application
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public base::SupportsWeakPtr<Application> {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Application(BackgroundApplicationListModel* model,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              const Extension* an_extension);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Application();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invoked when a request icon is available.
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnImageLoaded(const gfx::Image& image);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Uses the FILE thread to request this extension's icon, sized
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // appropriately.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RequestIcon(extension_misc::ExtensionIcons size);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<gfx::ImageSkia> icon_;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundApplicationListModel* model_;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetServiceApplications(ExtensionService* service,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            ExtensionList* applications_result) {
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionRegistry* registry = ExtensionRegistry::Get(service->profile());
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ExtensionSet& enabled_extensions = registry->enabled_extensions();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ExtensionSet::const_iterator cursor = enabled_extensions.begin();
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       cursor != enabled_extensions.end();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++cursor) {
1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const Extension* extension = cursor->get();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (BackgroundApplicationListModel::IsBackgroundApp(*extension,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        service->profile())) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      applications_result->push_back(extension);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Walk the list of terminated extensions also (just because an extension
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // crashed doesn't mean we should ignore it).
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ExtensionSet& terminated_extensions = registry->terminated_extensions();
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ExtensionSet::const_iterator cursor = terminated_extensions.begin();
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       cursor != terminated_extensions.end();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++cursor) {
1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const Extension* extension = cursor->get();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (BackgroundApplicationListModel::IsBackgroundApp(*extension,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        service->profile())) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      applications_result->push_back(extension);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string locale = g_browser_process->GetApplicationLocale();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::Locale loc(locale.c_str());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode error = U_ZERO_ERROR;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(loc, error));
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(applications_result->begin(), applications_result->end(),
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ExtensionNameComparator(collator.get()));
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::Observer::OnApplicationDataChanged(
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension, Profile* profile) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::Observer::OnApplicationListChanged(
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::Observer::~Observer() {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::Application::~Application() {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::Application::Application(
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BackgroundApplicationListModel* model,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension)
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : extension_(extension), model_(model) {}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::Application::OnImageLoaded(
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Image& image) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image.IsEmpty())
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_.reset(image.CopyImageSkia());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SendApplicationDataChangedNotifications(extension_);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::Application::RequestIcon(
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_misc::ExtensionIcons size) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extensions::ExtensionResource resource =
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::IconsInfo::GetIconResource(
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          extension_, size, ExtensionIconSet::MATCH_BIGGER);
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extensions::ImageLoader::Get(model_->profile_)->LoadImageAsync(
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_, resource, gfx::Size(size, size),
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&Application::OnImageLoaded, AsWeakPtr()));
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::~BackgroundApplicationListModel() {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteContainerPairSecondPointers(applications_.begin(),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       applications_.end());
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::BackgroundApplicationListModel(Profile* profile)
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : profile_(profile),
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ready_(false) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile_);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this,
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this,
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this,
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this,
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 chrome::NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* service = extensions::ExtensionSystem::Get(profile)->
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_service();
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (service && service->is_ready()) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Update();
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ready_ = true;
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::AddObserver(Observer* observer) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::AssociateApplicationData(
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsBackgroundApp(*extension, profile_));
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Application* application = FindApplication(extension);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!application) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // App position is used as a dynamic command and so must be less than any
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // predefined command id.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (applications_.size() >= IDC_MinimumLabelValue) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Background application limit of " << IDC_MinimumLabelValue
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " exceeded.  Ignoring.";
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    application = new Application(this, extension);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    applications_[extension->id()] = application;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Update();
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    application->RequestIcon(extension_misc::EXTENSION_ICON_BITTY);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::DissociateApplicationData(
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ApplicationMap::iterator found = applications_.find(extension->id());
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (found != applications_.end()) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete found->second;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    applications_.erase(found);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const Extension* BackgroundApplicationListModel::GetExtension(
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int position) const {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(position >= 0 && static_cast<size_t>(position) < extensions_.size());
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return extensions_[position].get();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BackgroundApplicationListModel::Application*
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::FindApplication(
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) const {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& id = extension->id();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ApplicationMap::const_iterator found = applications_.find(id);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (found == applications_.end()) ? NULL : found->second;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::Application*
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundApplicationListModel::FindApplication(
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& id = extension->id();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ApplicationMap::iterator found = applications_.find(id);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (found == applications_.end()) ? NULL : found->second;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::ImageSkia* BackgroundApplicationListModel::GetIcon(
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Application* application = FindApplication(extension);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (application)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return application->icon_.get();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AssociateApplicationData(extension);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundApplicationListModel::GetPosition(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) const {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int position = 0;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& id = extension->id();
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ExtensionList::const_iterator cursor = extensions_.begin();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       cursor != extensions_.end();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++cursor, ++position) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (id == cursor->get()->id())
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return position;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool BackgroundApplicationListModel::RequiresBackgroundModeForPushMessaging(
2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const Extension& extension) {
2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // No PushMessaging permission - does not require the background mode.
28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!extension.permissions_data()->HasAPIPermission(
28746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          APIPermission::kPushMessaging)) {
2881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return false;
28946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // If in the whitelist, then does not require background mode even if
2921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // uses push messaging.
2931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TODO(dimich): remove this whitelist once we have a better way to keep
2941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // listening for GCM. http://crbug.com/311268
2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string id_hash = base::SHA1HashString(extension.id());
2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(),
2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                   id_hash.length());
2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The id starting from "9A04..." is a one from unit test.
2991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (hexencoded_id_hash == "C41AD9DCD670210295614257EF8C9945AD68D86E" ||
3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      hexencoded_id_hash == "9A0417016F345C934A1A88F55CA17C05014EEEBA")
3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)     return false;
3021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)   return true;
3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) }
3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// static
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundApplicationListModel::IsBackgroundApp(
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension& extension, Profile* profile) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An extension is a "background app" if it has the "background API"
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // permission, and meets one of the following criteria:
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 1) It is an extension (not a hosted app).
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2) It is a hosted app, and has a background contents registered or in the
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    manifest.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Ephemeral apps are denied any background activity after their event page
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // has been destroyed, thus they cannot be background apps.
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (extensions::util::IsEphemeralApp(extension.id(), profile))
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not a background app if we don't have the background permission or
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the push messaging permission
32246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!extension.permissions_data()->HasAPIPermission(
32346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          APIPermission::kBackground) &&
3241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      !RequiresBackgroundModeForPushMessaging(extension))
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Extensions and packaged apps with background permission are always treated
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as background apps.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension.is_hosted_app())
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hosted apps with manifest-provided background pages are background apps.
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extensions::BackgroundInfo::HasBackgroundPage(&extension))
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundContentsService* service =
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BackgroundContentsServiceFactory::GetForProfile(profile);
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 app_id = base::ASCIIToUTF16(extension.id());
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have an active or registered background contents for this app, then
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it's a background app. This covers the cases where the app has created its
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // background contents, but it hasn't navigated yet, or the background
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // contents crashed and hasn't yet been restarted - in both cases we still
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to treat the app as a background app.
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (service->GetAppBackgroundContents(app_id) ||
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service->HasRegisteredBackgroundContents(app_id)) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Doesn't meet our criteria, so it's not a background app.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::Observe(
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationSource& source,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationDetails& details) {
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (type == extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Update();
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ready_ = true;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_service();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!service || !service->is_ready())
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED:
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OnExtensionLoaded(content::Details<Extension>(details).ptr());
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED:
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OnExtensionUnloaded(
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<UnloadedExtensionInfo>(details)->extension);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED:
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OnExtensionPermissionsUpdated(
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<UpdatedExtensionPermissionsInfo>(details)->extension,
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<UpdatedExtensionPermissionsInfo>(details)->reason,
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<UpdatedExtensionPermissionsInfo>(details)->
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              permissions);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED:
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Update();
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Received unexpected notification";
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::SendApplicationDataChangedNotifications(
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observers_, OnApplicationDataChanged(extension,
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                   profile_));
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::OnExtensionLoaded(
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only care about extensions that are background applications
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsBackgroundApp(*extension, profile_))
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AssociateApplicationData(extension);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::OnExtensionUnloaded(
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsBackgroundApp(*extension, profile_))
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Update();
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DissociateApplicationData(extension);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::OnExtensionPermissionsUpdated(
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension,
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdatedExtensionPermissionsInfo::Reason reason,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PermissionSet* permissions) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (permissions->HasAPIPermission(APIPermission::kBackground)) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (reason) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case UpdatedExtensionPermissionsInfo::ADDED:
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(IsBackgroundApp(*extension, profile_));
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnExtensionLoaded(extension);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case UpdatedExtensionPermissionsInfo::REMOVED:
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(!IsBackgroundApp(*extension, profile_));
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Update();
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DissociateApplicationData(extension);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::RemoveObserver(Observer* observer) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Update queries the extensions service of the profile with which the model was
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// initialized to determine the current set of background applications.  If that
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// differs from the old list, it generates OnApplicationListChanged events for
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each observer.
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundApplicationListModel::Update() {
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_service();
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Discover current background applications, compare with previous list, which
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is consistently sorted, and notify observers if they differ.
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionList extensions;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetServiceApplications(service, &extensions);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionList::const_iterator old_cursor = extensions_.begin();
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionList::const_iterator new_cursor = extensions.begin();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (old_cursor != extensions_.end() &&
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         new_cursor != extensions.end() &&
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (*old_cursor)->name() == (*new_cursor)->name() &&
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (*old_cursor)->id() == (*new_cursor)->id()) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++old_cursor;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++new_cursor;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_cursor != extensions_.end() || new_cursor != extensions.end()) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions_ = extensions;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(Observer, observers_, OnApplicationListChanged(profile_));
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
463