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