NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / ui / app_list / extension_app_model_builder.cc
blob56de1b93f5a44095bce331407e48d1f6c7992ae8
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.
5 #include "chrome/browser/ui/app_list/extension_app_model_builder.h"
7 #include <algorithm>
9 #include "base/auto_reset.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "base/prefs/pref_service.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/install_tracker.h"
16 #include "chrome/browser/extensions/install_tracker_factory.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
19 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
20 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
21 #include "chrome/browser/ui/app_list/extension_app_item.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/extensions/extension_constants.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/notification_service.h"
26 #include "extensions/browser/extension_prefs.h"
27 #include "extensions/browser/extension_system.h"
28 #include "extensions/browser/pref_names.h"
29 #include "extensions/common/extension.h"
30 #include "extensions/common/extension_set.h"
31 #include "ui/gfx/image/image_skia.h"
33 using extensions::Extension;
35 namespace {
37 bool ShouldDisplayInAppLauncher(Profile* profile,
38 scoped_refptr<const Extension> app) {
39 // If it's the web store, check the policy.
40 bool blocked_by_policy =
41 (app->id() == extension_misc::kWebStoreAppId ||
42 app->id() == extension_misc::kEnterpriseWebStoreAppId) &&
43 profile->GetPrefs()->GetBoolean(prefs::kHideWebStoreIcon);
44 return app->ShouldDisplayInAppLauncher() && !blocked_by_policy;
47 } // namespace
49 ExtensionAppModelBuilder::ExtensionAppModelBuilder(
50 AppListControllerDelegate* controller)
51 : service_(NULL),
52 profile_(NULL),
53 controller_(controller),
54 model_(NULL),
55 highlighted_app_pending_(false),
56 tracker_(NULL) {
59 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
60 OnShutdown();
61 model_->item_list()->RemoveObserver(this);
64 void ExtensionAppModelBuilder::InitializeWithService(
65 app_list::AppListSyncableService* service) {
66 DCHECK(!service_ && !profile_);
67 model_ = service->model();
68 model_->item_list()->AddObserver(this);
69 service_ = service;
70 profile_ = service->profile();
71 InitializePrefChangeRegistrar();
73 BuildModel();
76 void ExtensionAppModelBuilder::InitializeWithProfile(
77 Profile* profile,
78 app_list::AppListModel* model) {
79 DCHECK(!service_ && !profile_);
80 model_ = model;
81 model_->item_list()->AddObserver(this);
82 profile_ = profile;
83 InitializePrefChangeRegistrar();
85 BuildModel();
88 void ExtensionAppModelBuilder::InitializePrefChangeRegistrar() {
89 if (!CommandLine::ForCurrentProcess()->HasSwitch(
90 switches::kEnableStreamlinedHostedApps))
91 return;
93 const ExtensionService* extension_service =
94 extensions::ExtensionSystem::Get(profile_)->extension_service();
95 if (!extension_service)
96 return;
98 extension_pref_change_registrar_.Init(
99 extension_service->extension_prefs()->pref_service());
100 extension_pref_change_registrar_.Add(
101 extensions::pref_names::kExtensions,
102 base::Bind(&ExtensionAppModelBuilder::OnExtensionPreferenceChanged,
103 base::Unretained(this)));
106 void ExtensionAppModelBuilder::OnExtensionPreferenceChanged() {
107 // TODO(calamity): analyze the performance impact of doing this every
108 // extension pref change.
109 app_list::AppListItemList* item_list = model_->item_list();
110 for (size_t i = 0; i < item_list->item_count(); ++i) {
111 app_list::AppListItem* item = item_list->item_at(i);
112 if (item->GetItemType() != ExtensionAppItem::kItemType)
113 continue;
115 static_cast<ExtensionAppItem*>(item)->UpdateIconOverlay();
119 void ExtensionAppModelBuilder::OnBeginExtensionInstall(
120 const ExtensionInstallParams& params) {
121 if (!params.is_app || params.is_ephemeral)
122 return;
124 DVLOG(2) << service_ << ": OnBeginExtensionInstall: "
125 << params.extension_id.substr(0, 8);
126 ExtensionAppItem* existing_item = GetExtensionAppItem(params.extension_id);
127 if (existing_item) {
128 existing_item->SetIsInstalling(true);
129 return;
131 InsertApp(CreateAppItem(params.extension_id,
132 params.extension_name,
133 params.installing_icon,
134 params.is_platform_app));
135 SetHighlightedApp(params.extension_id);
138 void ExtensionAppModelBuilder::OnDownloadProgress(
139 const std::string& extension_id,
140 int percent_downloaded) {
141 ExtensionAppItem* item = GetExtensionAppItem(extension_id);
142 if (!item)
143 return;
144 item->SetPercentDownloaded(percent_downloaded);
147 void ExtensionAppModelBuilder::OnInstallFailure(
148 const std::string& extension_id) {
149 model_->DeleteItem(extension_id);
152 void ExtensionAppModelBuilder::OnExtensionLoaded(const Extension* extension) {
153 if (!extension->ShouldDisplayInAppLauncher())
154 return;
156 DVLOG(2) << service_ << ": OnExtensionLoaded: "
157 << extension->id().substr(0, 8);
158 ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
159 if (existing_item) {
160 existing_item->Reload();
161 return;
164 InsertApp(CreateAppItem(extension->id(),
166 gfx::ImageSkia(),
167 extension->is_platform_app()));
168 UpdateHighlight();
171 void ExtensionAppModelBuilder::OnExtensionUnloaded(const Extension* extension) {
172 ExtensionAppItem* item = GetExtensionAppItem(extension->id());
173 if (!item)
174 return;
175 item->UpdateIcon();
178 void ExtensionAppModelBuilder::OnExtensionUninstalled(
179 const Extension* extension) {
180 if (service_) {
181 DVLOG(2) << service_ << ": OnExtensionUninstalled: "
182 << extension->id().substr(0, 8);
183 service_->RemoveItem(extension->id());
184 return;
186 model_->DeleteItem(extension->id());
189 void ExtensionAppModelBuilder::OnAppsReordered() {
190 // Do nothing; App List order does not track extensions order.
193 void ExtensionAppModelBuilder::OnAppInstalledToAppList(
194 const std::string& extension_id) {
195 SetHighlightedApp(extension_id);
198 void ExtensionAppModelBuilder::OnShutdown() {
199 if (tracker_) {
200 tracker_->RemoveObserver(this);
201 tracker_ = NULL;
205 scoped_ptr<ExtensionAppItem> ExtensionAppModelBuilder::CreateAppItem(
206 const std::string& extension_id,
207 const std::string& extension_name,
208 const gfx::ImageSkia& installing_icon,
209 bool is_platform_app) {
210 const app_list::AppListSyncableService::SyncItem* sync_item =
211 service_ ? service_->GetSyncItem(extension_id) : NULL;
212 return make_scoped_ptr(new ExtensionAppItem(profile_,
213 sync_item,
214 extension_id,
215 extension_name,
216 installing_icon,
217 is_platform_app));
220 void ExtensionAppModelBuilder::BuildModel() {
221 DCHECK(!tracker_);
222 tracker_ = controller_->GetInstallTrackerFor(profile_);
224 PopulateApps();
225 UpdateHighlight();
227 // Start observing after model is built.
228 if (tracker_)
229 tracker_->AddObserver(this);
232 void ExtensionAppModelBuilder::PopulateApps() {
233 extensions::ExtensionSet extensions;
234 controller_->GetApps(profile_, &extensions);
236 for (extensions::ExtensionSet::const_iterator app = extensions.begin();
237 app != extensions.end(); ++app) {
238 if (!ShouldDisplayInAppLauncher(profile_, *app))
239 continue;
240 InsertApp(CreateAppItem((*app)->id(),
242 gfx::ImageSkia(),
243 (*app)->is_platform_app()));
247 void ExtensionAppModelBuilder::InsertApp(scoped_ptr<ExtensionAppItem> app) {
248 if (service_) {
249 service_->AddItem(app.PassAs<app_list::AppListItem>());
250 return;
252 model_->AddItem(app.PassAs<app_list::AppListItem>());
255 void ExtensionAppModelBuilder::SetHighlightedApp(
256 const std::string& extension_id) {
257 if (extension_id == highlight_app_id_)
258 return;
259 ExtensionAppItem* old_app = GetExtensionAppItem(highlight_app_id_);
260 if (old_app)
261 old_app->SetHighlighted(false);
262 highlight_app_id_ = extension_id;
263 ExtensionAppItem* new_app = GetExtensionAppItem(highlight_app_id_);
264 highlighted_app_pending_ = !new_app;
265 if (new_app)
266 new_app->SetHighlighted(true);
269 ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
270 const std::string& extension_id) {
271 app_list::AppListItem* item =
272 model_->item_list()->FindItem(extension_id);
273 LOG_IF(ERROR, item &&
274 item->GetItemType() != ExtensionAppItem::kItemType)
275 << "App Item matching id: " << extension_id
276 << " has incorrect type: '" << item->GetItemType() << "'";
277 return static_cast<ExtensionAppItem*>(item);
280 void ExtensionAppModelBuilder::UpdateHighlight() {
281 DCHECK(model_);
282 if (!highlighted_app_pending_ || highlight_app_id_.empty())
283 return;
284 ExtensionAppItem* item = GetExtensionAppItem(highlight_app_id_);
285 if (!item)
286 return;
287 item->SetHighlighted(true);
288 highlighted_app_pending_ = false;
291 void ExtensionAppModelBuilder::OnListItemMoved(size_t from_index,
292 size_t to_index,
293 app_list::AppListItem* item) {
294 // This will get called from AppListItemList::ListItemMoved after
295 // set_position is called for the item.
296 app_list::AppListItemList* item_list = model_->item_list();
297 if (item->GetItemType() != ExtensionAppItem::kItemType)
298 return;
300 if (service_)
301 return;
303 ExtensionAppItem* prev = NULL;
304 for (size_t idx = to_index; idx > 0; --idx) {
305 app_list::AppListItem* item = item_list->item_at(idx - 1);
306 if (item->GetItemType() == ExtensionAppItem::kItemType) {
307 prev = static_cast<ExtensionAppItem*>(item);
308 break;
311 ExtensionAppItem* next = NULL;
312 for (size_t idx = to_index; idx < item_list->item_count() - 1; ++idx) {
313 app_list::AppListItem* item = item_list->item_at(idx + 1);
314 if (item->GetItemType() == ExtensionAppItem::kItemType) {
315 next = static_cast<ExtensionAppItem*>(item);
316 break;
319 // item->Move will call set_position, overriding the item's position.
320 if (prev || next)
321 static_cast<ExtensionAppItem*>(item)->Move(prev, next);