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"
9 #include "base/auto_reset.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/extensions/extension_prefs.h"
13 #include "chrome/browser/extensions/install_tracker.h"
14 #include "chrome/browser/extensions/install_tracker_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
17 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
18 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
19 #include "chrome/browser/ui/app_list/extension_app_item.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/common/pref_names.h"
22 #include "content/public/browser/notification_service.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "ui/gfx/image/image_skia.h"
27 using extensions::Extension
;
31 bool ShouldDisplayInAppLauncher(Profile
* profile
,
32 scoped_refptr
<const Extension
> app
) {
33 // If it's the web store, check the policy.
34 bool blocked_by_policy
=
35 (app
->id() == extension_misc::kWebStoreAppId
||
36 app
->id() == extension_misc::kEnterpriseWebStoreAppId
) &&
37 profile
->GetPrefs()->GetBoolean(prefs::kHideWebStoreIcon
);
38 return app
->ShouldDisplayInAppLauncher() && !blocked_by_policy
;
43 ExtensionAppModelBuilder::ExtensionAppModelBuilder(
44 AppListControllerDelegate
* controller
)
47 controller_(controller
),
49 highlighted_app_pending_(false),
53 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
55 model_
->item_list()->RemoveObserver(this);
58 void ExtensionAppModelBuilder::InitializeWithService(
59 app_list::AppListSyncableService
* service
) {
60 model_
= service
->model();
61 model_
->item_list()->AddObserver(this);
63 profile_
= service
->profile();
67 void ExtensionAppModelBuilder::InitializeWithProfile(
69 app_list::AppListModel
* model
) {
71 model_
->item_list()->AddObserver(this);
76 void ExtensionAppModelBuilder::OnBeginExtensionInstall(
77 const ExtensionInstallParams
& params
) {
78 if (!params
.is_app
|| params
.is_ephemeral
)
81 DVLOG(2) << service_
<< ": OnBeginExtensionInstall: "
82 << params
.extension_id
.substr(0, 8);
83 ExtensionAppItem
* existing_item
= GetExtensionAppItem(params
.extension_id
);
85 existing_item
->SetIsInstalling(true);
88 InsertApp(CreateAppItem(params
.extension_id
,
89 params
.extension_name
,
90 params
.installing_icon
,
91 params
.is_platform_app
));
92 SetHighlightedApp(params
.extension_id
);
95 void ExtensionAppModelBuilder::OnDownloadProgress(
96 const std::string
& extension_id
,
97 int percent_downloaded
) {
98 ExtensionAppItem
* item
= GetExtensionAppItem(extension_id
);
101 item
->SetPercentDownloaded(percent_downloaded
);
104 void ExtensionAppModelBuilder::OnInstallFailure(
105 const std::string
& extension_id
) {
106 model_
->item_list()->DeleteItem(extension_id
);
109 void ExtensionAppModelBuilder::OnExtensionLoaded(const Extension
* extension
) {
110 if (!extension
->ShouldDisplayInAppLauncher())
113 DVLOG(2) << service_
<< ": OnExtensionLoaded: "
114 << extension
->id().substr(0, 8);
115 ExtensionAppItem
* existing_item
= GetExtensionAppItem(extension
->id());
117 existing_item
->Reload();
121 InsertApp(CreateAppItem(extension
->id(),
124 extension
->is_platform_app()));
128 void ExtensionAppModelBuilder::OnExtensionUnloaded(const Extension
* extension
) {
129 ExtensionAppItem
* item
= GetExtensionAppItem(extension
->id());
135 void ExtensionAppModelBuilder::OnExtensionUninstalled(
136 const Extension
* extension
) {
138 DVLOG(2) << service_
<< ": OnExtensionUninstalled: "
139 << extension
->id().substr(0, 8);
140 service_
->RemoveItem(extension
->id());
143 model_
->item_list()->DeleteItem(extension
->id());
146 void ExtensionAppModelBuilder::OnAppsReordered() {
147 // Do nothing; App List order does not track extensions order.
150 void ExtensionAppModelBuilder::OnAppInstalledToAppList(
151 const std::string
& extension_id
) {
152 SetHighlightedApp(extension_id
);
155 void ExtensionAppModelBuilder::OnShutdown() {
157 tracker_
->RemoveObserver(this);
162 ExtensionAppItem
* ExtensionAppModelBuilder::CreateAppItem(
163 const std::string
& extension_id
,
164 const std::string
& extension_name
,
165 const gfx::ImageSkia
& installing_icon
,
166 bool is_platform_app
) {
167 const app_list::AppListSyncableService::SyncItem
* sync_item
=
168 service_
? service_
->GetSyncItem(extension_id
) : NULL
;
169 return new ExtensionAppItem(profile_
,
177 void ExtensionAppModelBuilder::AddApps(
178 const extensions::ExtensionSet
* extensions
,
179 ExtensionAppList
* apps
) {
180 for (extensions::ExtensionSet::const_iterator app
= extensions
->begin();
181 app
!= extensions
->end(); ++app
) {
182 if (ShouldDisplayInAppLauncher(profile_
, *app
)) {
183 apps
->push_back(CreateAppItem((*app
)->id(),
186 (*app
)->is_platform_app()));
191 void ExtensionAppModelBuilder::BuildModel() {
192 // Delete any extension apps.
193 model_
->item_list()->DeleteItemsByType(ExtensionAppItem::kAppType
);
196 tracker_
->RemoveObserver(this);
198 tracker_
= controller_
->GetInstallTrackerFor(profile_
);
203 // Start observing after model is built.
205 tracker_
->AddObserver(this);
208 void ExtensionAppModelBuilder::PopulateApps() {
209 extensions::ExtensionSet extensions
;
210 controller_
->GetApps(profile_
, &extensions
);
211 ExtensionAppList apps
;
212 AddApps(&extensions
, &apps
);
217 for (size_t i
= 0; i
< apps
.size(); ++i
)
221 void ExtensionAppModelBuilder::InsertApp(ExtensionAppItem
* app
) {
223 service_
->AddItem(app
);
226 model_
->item_list()->AddItem(app
);
229 void ExtensionAppModelBuilder::SetHighlightedApp(
230 const std::string
& extension_id
) {
231 if (extension_id
== highlight_app_id_
)
233 ExtensionAppItem
* old_app
= GetExtensionAppItem(highlight_app_id_
);
235 old_app
->SetHighlighted(false);
236 highlight_app_id_
= extension_id
;
237 ExtensionAppItem
* new_app
= GetExtensionAppItem(highlight_app_id_
);
238 highlighted_app_pending_
= !new_app
;
240 new_app
->SetHighlighted(true);
243 ExtensionAppItem
* ExtensionAppModelBuilder::GetExtensionAppItem(
244 const std::string
& extension_id
) {
245 app_list::AppListItem
* item
=
246 model_
->item_list()->FindItem(extension_id
);
247 LOG_IF(ERROR
, item
&&
248 item
->GetAppType() != ExtensionAppItem::kAppType
)
249 << "App Item matching id: " << extension_id
250 << " has incorrect type: '" << item
->GetAppType() << "'";
251 return static_cast<ExtensionAppItem
*>(item
);
254 void ExtensionAppModelBuilder::UpdateHighlight() {
256 if (!highlighted_app_pending_
|| highlight_app_id_
.empty())
258 ExtensionAppItem
* item
= GetExtensionAppItem(highlight_app_id_
);
261 item
->SetHighlighted(true);
262 highlighted_app_pending_
= false;
265 void ExtensionAppModelBuilder::OnListItemMoved(size_t from_index
,
267 app_list::AppListItem
* item
) {
268 // This will get called from AppListItemList::ListItemMoved after
269 // set_position is called for the item.
270 app_list::AppListItemList
* item_list
= model_
->item_list();
271 if (item
->GetAppType() != ExtensionAppItem::kAppType
)
275 service_
->UpdateItem(item
);
279 ExtensionAppItem
* prev
= NULL
;
280 for (size_t idx
= to_index
; idx
> 0; --idx
) {
281 app_list::AppListItem
* item
= item_list
->item_at(idx
- 1);
282 if (item
->GetAppType() == ExtensionAppItem::kAppType
) {
283 prev
= static_cast<ExtensionAppItem
*>(item
);
287 ExtensionAppItem
* next
= NULL
;
288 for (size_t idx
= to_index
; idx
< item_list
->item_count() - 1; ++idx
) {
289 app_list::AppListItem
* item
= item_list
->item_at(idx
+ 1);
290 if (item
->GetAppType() == ExtensionAppItem::kAppType
) {
291 next
= static_cast<ExtensionAppItem
*>(item
);
295 // item->Move will call set_position, overriding the item's position.
297 static_cast<ExtensionAppItem
*>(item
)->Move(prev
, next
);