1 // Copyright 2015 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/chrome_app_list_item.h"
6 
7 #include <utility>
8 
9 #include "ash/public/cpp/tablet_mode.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
12 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
13 #include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
14 #include "extensions/browser/app_sorting.h"
15 #include "extensions/browser/extension_system.h"
16 #include "ui/gfx/color_utils.h"
17 #include "ui/gfx/image/image_skia_operations.h"
18 
19 #if defined(OS_CHROMEOS)
20 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
21 #endif
22 
23 namespace {
24 
25 AppListControllerDelegate* g_controller_for_test = nullptr;
26 
CreateDefaultMetadata(const std::string & app_id)27 std::unique_ptr<ash::AppListItemMetadata> CreateDefaultMetadata(
28     const std::string& app_id) {
29   auto metadata = std::make_unique<ash::AppListItemMetadata>();
30   metadata->id = app_id;
31   return metadata;
32 }
33 
34 }  // namespace
35 
36 // static
OverrideAppListControllerDelegateForTesting(AppListControllerDelegate * controller)37 void ChromeAppListItem::OverrideAppListControllerDelegateForTesting(
38     AppListControllerDelegate* controller) {
39   g_controller_for_test = controller;
40 }
41 
42 // static
CreateDisabledIcon(const gfx::ImageSkia & icon)43 gfx::ImageSkia ChromeAppListItem::CreateDisabledIcon(
44     const gfx::ImageSkia& icon) {
45   const color_utils::HSL shift = {-1, 0, 0.6};
46   return gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
47 }
48 
49 // ChromeAppListItem::TestApi
TestApi(ChromeAppListItem * item)50 ChromeAppListItem::TestApi::TestApi(ChromeAppListItem* item) : item_(item) {}
51 
SetFolderId(const std::string & folder_id)52 void ChromeAppListItem::TestApi::SetFolderId(const std::string& folder_id) {
53   item_->SetFolderId(folder_id);
54 }
55 
SetPosition(const syncer::StringOrdinal & position)56 void ChromeAppListItem::TestApi::SetPosition(
57     const syncer::StringOrdinal& position) {
58   item_->SetPosition(position);
59 }
60 
61 // ChromeAppListItem
ChromeAppListItem(Profile * profile,const std::string & app_id)62 ChromeAppListItem::ChromeAppListItem(Profile* profile,
63                                      const std::string& app_id)
64     : metadata_(CreateDefaultMetadata(app_id)), profile_(profile) {}
65 
ChromeAppListItem(Profile * profile,const std::string & app_id,AppListModelUpdater * model_updater)66 ChromeAppListItem::ChromeAppListItem(Profile* profile,
67                                      const std::string& app_id,
68                                      AppListModelUpdater* model_updater)
69     : metadata_(CreateDefaultMetadata(app_id)),
70       profile_(profile),
71       model_updater_(model_updater) {}
72 
73 ChromeAppListItem::~ChromeAppListItem() = default;
74 
SetMetadata(std::unique_ptr<ash::AppListItemMetadata> metadata)75 void ChromeAppListItem::SetMetadata(
76     std::unique_ptr<ash::AppListItemMetadata> metadata) {
77   metadata_ = std::move(metadata);
78 }
79 
CloneMetadata() const80 std::unique_ptr<ash::AppListItemMetadata> ChromeAppListItem::CloneMetadata()
81     const {
82   return std::make_unique<ash::AppListItemMetadata>(*metadata_);
83 }
84 
PerformActivate(int event_flags)85 void ChromeAppListItem::PerformActivate(int event_flags) {
86 #if defined(OS_CHROMEOS)
87   // Handle recording app launch source from the AppList in Demo Mode.
88   chromeos::DemoSession::RecordAppLaunchSourceIfInDemoMode(
89       chromeos::DemoSession::AppLaunchSource::kAppList);
90 #endif
91   Activate(event_flags);
92   MaybeDismissAppList();
93 }
94 
Activate(int event_flags)95 void ChromeAppListItem::Activate(int event_flags) {}
96 
GetItemType() const97 const char* ChromeAppListItem::GetItemType() const {
98   return "";
99 }
100 
GetContextMenuModel(GetMenuModelCallback callback)101 void ChromeAppListItem::GetContextMenuModel(GetMenuModelCallback callback) {
102   std::move(callback).Run(nullptr);
103 }
104 
IsBadged() const105 bool ChromeAppListItem::IsBadged() const {
106   return false;
107 }
108 
GetAppContextMenu()109 app_list::AppContextMenu* ChromeAppListItem::GetAppContextMenu() {
110   return nullptr;
111 }
112 
MaybeDismissAppList()113 void ChromeAppListItem::MaybeDismissAppList() {
114   // Launching apps can take some time. It looks nicer to dismiss the app list.
115   // Do not close app list for home launcher.
116   if (!ash::TabletMode::Get() || !ash::TabletMode::Get()->InTabletMode()) {
117     GetController()->DismissView();
118   }
119 }
120 
GetAppSorting()121 extensions::AppSorting* ChromeAppListItem::GetAppSorting() {
122   return extensions::ExtensionSystem::Get(profile())->app_sorting();
123 }
124 
GetController()125 AppListControllerDelegate* ChromeAppListItem::GetController() {
126   return g_controller_for_test != nullptr ? g_controller_for_test
127                                           : AppListClientImpl::GetInstance();
128 }
129 
UpdateFromSync(const app_list::AppListSyncableService::SyncItem * sync_item)130 void ChromeAppListItem::UpdateFromSync(
131     const app_list::AppListSyncableService::SyncItem* sync_item) {
132   DCHECK(sync_item && sync_item->item_ordinal.IsValid());
133   // An existing synced position exists, use that.
134   SetPosition(sync_item->item_ordinal);
135   // Only set the name from the sync item if it is empty.
136   if (name().empty())
137     SetName(sync_item->item_name);
138 }
139 
SetDefaultPositionIfApplicable(AppListModelUpdater * model_updater)140 void ChromeAppListItem::SetDefaultPositionIfApplicable(
141     AppListModelUpdater* model_updater) {
142   syncer::StringOrdinal page_ordinal;
143   syncer::StringOrdinal launch_ordinal;
144   extensions::AppSorting* app_sorting = GetAppSorting();
145   if (app_sorting->GetDefaultOrdinals(id(), &page_ordinal, &launch_ordinal) &&
146       page_ordinal.IsValid() && launch_ordinal.IsValid()) {
147     // Set the default position if it exists.
148     SetPosition(syncer::StringOrdinal(page_ordinal.ToInternalValue() +
149                                       launch_ordinal.ToInternalValue()));
150     return;
151   }
152 
153   if (model_updater) {
154     // Set the first available position in the app list.
155     SetPosition(model_updater->GetFirstAvailablePosition());
156     return;
157   }
158 
159   // Set the natural position.
160   app_sorting->EnsureValidOrdinals(id(), syncer::StringOrdinal());
161   page_ordinal = app_sorting->GetPageOrdinal(id());
162   launch_ordinal = app_sorting->GetAppLaunchOrdinal(id());
163   SetPosition(syncer::StringOrdinal(page_ordinal.ToInternalValue() +
164                                     launch_ordinal.ToInternalValue()));
165 }
166 
SetIcon(const gfx::ImageSkia & icon)167 void ChromeAppListItem::SetIcon(const gfx::ImageSkia& icon) {
168   metadata_->icon = icon;
169   metadata_->icon.EnsureRepsForSupportedScales();
170   AppListModelUpdater* updater = model_updater();
171   if (updater)
172     updater->SetItemIcon(id(), metadata_->icon);
173 }
174 
SetName(const std::string & name)175 void ChromeAppListItem::SetName(const std::string& name) {
176   metadata_->name = name;
177   AppListModelUpdater* updater = model_updater();
178   if (updater)
179     updater->SetItemName(id(), name);
180 }
181 
SetNameAndShortName(const std::string & name,const std::string & short_name)182 void ChromeAppListItem::SetNameAndShortName(const std::string& name,
183                                             const std::string& short_name) {
184   metadata_->name = name;
185   AppListModelUpdater* updater = model_updater();
186   if (updater)
187     updater->SetItemNameAndShortName(id(), name, short_name);
188 }
189 
SetFolderId(const std::string & folder_id)190 void ChromeAppListItem::SetFolderId(const std::string& folder_id) {
191   metadata_->folder_id = folder_id;
192   AppListModelUpdater* updater = model_updater();
193   if (updater)
194     updater->SetItemFolderId(id(), folder_id);
195 }
196 
SetPosition(const syncer::StringOrdinal & position)197 void ChromeAppListItem::SetPosition(const syncer::StringOrdinal& position) {
198   metadata_->position = position;
199   AppListModelUpdater* updater = model_updater();
200   if (updater)
201     updater->SetItemPosition(id(), position);
202 }
203 
SetIsPersistent(bool is_persistent)204 void ChromeAppListItem::SetIsPersistent(bool is_persistent) {
205   metadata_->is_persistent = is_persistent;
206   AppListModelUpdater* updater = model_updater();
207   if (updater)
208     updater->SetItemIsPersistent(id(), is_persistent);
209 }
210 
SetIsPageBreak(bool is_page_break)211 void ChromeAppListItem::SetIsPageBreak(bool is_page_break) {
212   metadata_->is_page_break = is_page_break;
213 }
214 
SetChromeFolderId(const std::string & folder_id)215 void ChromeAppListItem::SetChromeFolderId(const std::string& folder_id) {
216   metadata_->folder_id = folder_id;
217 }
218 
SetChromeIsFolder(bool is_folder)219 void ChromeAppListItem::SetChromeIsFolder(bool is_folder) {
220   metadata_->is_folder = is_folder;
221 }
222 
SetChromeName(const std::string & name)223 void ChromeAppListItem::SetChromeName(const std::string& name) {
224   metadata_->name = name;
225 }
226 
SetChromePosition(const syncer::StringOrdinal & position)227 void ChromeAppListItem::SetChromePosition(
228     const syncer::StringOrdinal& position) {
229   metadata_->position = position;
230 }
231 
CompareForTest(const ChromeAppListItem * other) const232 bool ChromeAppListItem::CompareForTest(const ChromeAppListItem* other) const {
233   return id() == other->id() && folder_id() == other->folder_id() &&
234          name() == other->name() && GetItemType() == other->GetItemType() &&
235          position().Equals(other->position());
236 }
237 
ToDebugString() const238 std::string ChromeAppListItem::ToDebugString() const {
239   return id().substr(0, 8) + " '" + name() + "' (" + folder_id() + ") [" +
240          position().ToDebugString() + "]";
241 }
242