Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / extension_app_model_builder.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/app_list/extension_app_model_builder.h"
6
7 #include <algorithm>
8
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_service.h"
13 #include "chrome/browser/extensions/extension_system.h"
14 #include "chrome/browser/extensions/install_tracker.h"
15 #include "chrome/browser/extensions/install_tracker_factory.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
18 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
19 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
20 #include "chrome/browser/ui/app_list/extension_app_item.h"
21 #include "chrome/common/extensions/extension_constants.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/notification_service.h"
24 #include "extensions/browser/extension_prefs.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/extension_set.h"
27 #include "ui/gfx/image/image_skia.h"
28
29 using extensions::Extension;
30
31 namespace {
32
33 bool ShouldDisplayInAppLauncher(Profile* profile,
34                                 scoped_refptr<const Extension> app) {
35   // If it's the web store, check the policy.
36   bool blocked_by_policy =
37       (app->id() == extension_misc::kWebStoreAppId ||
38        app->id() == extension_misc::kEnterpriseWebStoreAppId) &&
39       profile->GetPrefs()->GetBoolean(prefs::kHideWebStoreIcon);
40   return app->ShouldDisplayInAppLauncher() && !blocked_by_policy;
41 }
42
43 }  // namespace
44
45 ExtensionAppModelBuilder::ExtensionAppModelBuilder(
46     AppListControllerDelegate* controller)
47     : service_(NULL),
48       profile_(NULL),
49       controller_(controller),
50       model_(NULL),
51       highlighted_app_pending_(false),
52       tracker_(NULL) {
53 }
54
55 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
56   OnShutdown();
57   model_->item_list()->RemoveObserver(this);
58 }
59
60 void ExtensionAppModelBuilder::InitializeWithService(
61     app_list::AppListSyncableService* service) {
62   model_ = service->model();
63   model_->item_list()->AddObserver(this);
64   service_ = service;
65   profile_ = service->profile();
66   BuildModel();
67 }
68
69 void ExtensionAppModelBuilder::InitializeWithProfile(
70     Profile* profile,
71     app_list::AppListModel* model) {
72   model_ = model;
73   model_->item_list()->AddObserver(this);
74   profile_ = profile;
75   BuildModel();
76 }
77
78 void ExtensionAppModelBuilder::OnBeginExtensionInstall(
79     const ExtensionInstallParams& params) {
80   if (!params.is_app || params.is_ephemeral)
81     return;
82
83   DVLOG(2) << service_ << ": OnBeginExtensionInstall: "
84            << params.extension_id.substr(0, 8);
85   ExtensionAppItem* existing_item = GetExtensionAppItem(params.extension_id);
86   if (existing_item) {
87     existing_item->SetIsInstalling(true);
88     return;
89   }
90   InsertApp(CreateAppItem(params.extension_id,
91                           params.extension_name,
92                           params.installing_icon,
93                           params.is_platform_app));
94   SetHighlightedApp(params.extension_id);
95 }
96
97 void ExtensionAppModelBuilder::OnDownloadProgress(
98     const std::string& extension_id,
99     int percent_downloaded) {
100   ExtensionAppItem* item = GetExtensionAppItem(extension_id);
101   if (!item)
102     return;
103   item->SetPercentDownloaded(percent_downloaded);
104 }
105
106 void ExtensionAppModelBuilder::OnInstallFailure(
107     const std::string& extension_id) {
108   model_->item_list()->DeleteItem(extension_id);
109 }
110
111 void ExtensionAppModelBuilder::OnExtensionLoaded(const Extension* extension) {
112   if (!extension->ShouldDisplayInAppLauncher())
113     return;
114
115   DVLOG(2) << service_ << ": OnExtensionLoaded: "
116            << extension->id().substr(0, 8);
117   ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
118   if (existing_item) {
119     existing_item->Reload();
120     return;
121   }
122
123   InsertApp(CreateAppItem(extension->id(),
124                           "",
125                           gfx::ImageSkia(),
126                           extension->is_platform_app()));
127   UpdateHighlight();
128 }
129
130 void ExtensionAppModelBuilder::OnExtensionUnloaded(const Extension* extension) {
131   ExtensionAppItem* item = GetExtensionAppItem(extension->id());
132   if (!item)
133     return;
134   item->UpdateIcon();
135 }
136
137 void ExtensionAppModelBuilder::OnExtensionUninstalled(
138     const Extension* extension) {
139   if (service_) {
140     DVLOG(2) << service_ << ": OnExtensionUninstalled: "
141              << extension->id().substr(0, 8);
142     service_->RemoveItem(extension->id());
143     return;
144   }
145   model_->item_list()->DeleteItem(extension->id());
146 }
147
148 void ExtensionAppModelBuilder::OnAppsReordered() {
149   // Do nothing; App List order does not track extensions order.
150 }
151
152 void ExtensionAppModelBuilder::OnAppInstalledToAppList(
153     const std::string& extension_id) {
154   SetHighlightedApp(extension_id);
155 }
156
157 void ExtensionAppModelBuilder::OnShutdown() {
158   if (tracker_) {
159     tracker_->RemoveObserver(this);
160     tracker_ = NULL;
161   }
162 }
163
164 ExtensionAppItem* ExtensionAppModelBuilder::CreateAppItem(
165     const std::string& extension_id,
166     const std::string& extension_name,
167     const gfx::ImageSkia& installing_icon,
168     bool is_platform_app) {
169   const app_list::AppListSyncableService::SyncItem* sync_item =
170       service_ ? service_->GetSyncItem(extension_id) : NULL;
171   return new ExtensionAppItem(profile_,
172                               sync_item,
173                               extension_id,
174                               extension_name,
175                               installing_icon,
176                               is_platform_app);
177 }
178
179 void ExtensionAppModelBuilder::AddApps(
180     const extensions::ExtensionSet* extensions,
181     ExtensionAppList* apps) {
182   for (extensions::ExtensionSet::const_iterator app = extensions->begin();
183        app != extensions->end(); ++app) {
184     if (ShouldDisplayInAppLauncher(profile_, *app)) {
185       apps->push_back(CreateAppItem((*app)->id(),
186                                     "",
187                                     gfx::ImageSkia(),
188                                     (*app)->is_platform_app()));
189     }
190   }
191 }
192
193 void ExtensionAppModelBuilder::BuildModel() {
194   // Delete any extension apps.
195   model_->item_list()->DeleteItemsByType(ExtensionAppItem::kItemType);
196
197   if (tracker_)
198     tracker_->RemoveObserver(this);
199
200   tracker_ = controller_->GetInstallTrackerFor(profile_);
201
202   PopulateApps();
203   UpdateHighlight();
204
205   // Start observing after model is built.
206   if (tracker_)
207     tracker_->AddObserver(this);
208 }
209
210 void ExtensionAppModelBuilder::PopulateApps() {
211   extensions::ExtensionSet extensions;
212   controller_->GetApps(profile_, &extensions);
213   ExtensionAppList apps;
214   AddApps(&extensions, &apps);
215
216   if (apps.empty())
217     return;
218
219   for (size_t i = 0; i < apps.size(); ++i)
220     InsertApp(apps[i]);
221 }
222
223 void ExtensionAppModelBuilder::InsertApp(ExtensionAppItem* app) {
224   if (service_) {
225     service_->AddItem(app);
226     return;
227   }
228   model_->item_list()->AddItem(app);
229 }
230
231 void ExtensionAppModelBuilder::SetHighlightedApp(
232     const std::string& extension_id) {
233   if (extension_id == highlight_app_id_)
234     return;
235   ExtensionAppItem* old_app = GetExtensionAppItem(highlight_app_id_);
236   if (old_app)
237     old_app->SetHighlighted(false);
238   highlight_app_id_ = extension_id;
239   ExtensionAppItem* new_app = GetExtensionAppItem(highlight_app_id_);
240   highlighted_app_pending_ = !new_app;
241   if (new_app)
242     new_app->SetHighlighted(true);
243 }
244
245 ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
246     const std::string& extension_id) {
247   app_list::AppListItem* item =
248       model_->item_list()->FindItem(extension_id);
249   LOG_IF(ERROR, item &&
250          item->GetItemType() != ExtensionAppItem::kItemType)
251       << "App Item matching id: " << extension_id
252       << " has incorrect type: '" << item->GetItemType() << "'";
253   return static_cast<ExtensionAppItem*>(item);
254 }
255
256 void ExtensionAppModelBuilder::UpdateHighlight() {
257   DCHECK(model_);
258   if (!highlighted_app_pending_ || highlight_app_id_.empty())
259     return;
260   ExtensionAppItem* item = GetExtensionAppItem(highlight_app_id_);
261   if (!item)
262     return;
263   item->SetHighlighted(true);
264   highlighted_app_pending_ = false;
265 }
266
267 void ExtensionAppModelBuilder::OnListItemMoved(size_t from_index,
268                                                size_t to_index,
269                                                app_list::AppListItem* item) {
270   // This will get called from AppListItemList::ListItemMoved after
271   // set_position is called for the item.
272   app_list::AppListItemList* item_list = model_->item_list();
273   if (item->GetItemType() != ExtensionAppItem::kItemType)
274     return;
275
276   if (service_)
277     return;
278
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->GetItemType() == ExtensionAppItem::kItemType) {
283       prev = static_cast<ExtensionAppItem*>(item);
284       break;
285     }
286   }
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->GetItemType() == ExtensionAppItem::kItemType) {
291       next = static_cast<ExtensionAppItem*>(item);
292       break;
293     }
294   }
295   // item->Move will call set_position, overriding the item's position.
296   if (prev || next)
297     static_cast<ExtensionAppItem*>(item)->Move(prev, next);
298 }