Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc

Issue 2055553004: arc: Support pinned apps across Arc-enabled and Arc-disabled platforms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <vector> 9 #include <vector>
10 10
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 const char* local_path, 128 const char* local_path,
129 const char* synced_path) { 129 const char* synced_path) {
130 if (!pref_service->FindPreference(local_path)->HasUserSetting() && 130 if (!pref_service->FindPreference(local_path)->HasUserSetting() &&
131 pref_service->IsSyncing()) { 131 pref_service->IsSyncing()) {
132 // First time the user is using this machine, propagate from remote to 132 // First time the user is using this machine, propagate from remote to
133 // local. 133 // local.
134 pref_service->SetString(local_path, pref_service->GetString(synced_path)); 134 pref_service->SetString(local_path, pref_service->GetString(synced_path));
135 } 135 }
136 } 136 }
137 137
138 /*
139 * Return whether an app is pinned only by user.
140 * This function doesn't expect an app_id neither pinned by user nor by
141 * policy, the app_id in the arguments list MUST be pinned by either of
142 * those. Invalid input may lead to unexpected result.
143 * If this app is pinned by policy, but not by user, false is returned.
144 * If this app is pinned by both policy and user, false is returned.
145 * If this app is pinned not by policy, but by user, true is returned.
146 */
147 bool IsAppForUserPinned(const std::string& app_id,
148 const base::ListValue* pinned_apps_pref,
149 const base::ListValue* policy_pinned_apps_pref) {
150 for (size_t index = 0; index < pinned_apps_pref->GetSize(); ++index) {
151 const base::DictionaryValue* app;
152 if (pinned_apps_pref->GetDictionary(index, &app)) {
153 std::string current_app_id;
154 bool pinned_by_policy = false;
155 if (app->GetString(ash::kPinnedAppsPrefAppIDPath, &current_app_id)) {
156 if (app_id == current_app_id) {
157 if (app->GetBoolean(ash::kPinnedAppsPrefPinnedByPolicy,
158 &pinned_by_policy) &&
159 pinned_by_policy) {
160 // Pinned by policy in the past or present.
161 // Need to check policy_pinned_apps to determine
162 break;
163 } else {
164 // User Preference Already Pinned
165 return true;
166 }
167 }
168 }
169 }
170 }
171 for (size_t index = 0; index < policy_pinned_apps_pref->GetSize(); ++index) {
172 const base::DictionaryValue* app;
173 if (policy_pinned_apps_pref->GetDictionary(index, &app)) {
174 std::string app_id_;
175 if (app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id_)) {
176 // Only pinned by policy, which is not part of user-pinned
177 if (app_id == app_id_)
178 return false;
179 }
180 }
181 }
182 // Default, user added new pins
183 return true;
184 }
185
186 const char* const kPinProhibitedExtensionIds[] = { 138 const char* const kPinProhibitedExtensionIds[] = {
187 ArcSupportHost::kHostAppId, arc::kPlayStoreAppId, 139 ArcSupportHost::kHostAppId, arc::kPlayStoreAppId,
188 }; 140 };
189 141
190 const size_t kPinProhibitedExtensionIdsLength = 142 const size_t kPinProhibitedExtensionIdsLength =
191 arraysize(kPinProhibitedExtensionIds); 143 arraysize(kPinProhibitedExtensionIds);
192 144
193 } // namespace 145 } // namespace
194 146
195 // A class to get events from ChromeOS when a user gets changed or added. 147 // A class to get events from ChromeOS when a user gets changed or added.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 209
258 void ChromeLauncherControllerUserSwitchObserver::AddUser(Profile* profile) { 210 void ChromeLauncherControllerUserSwitchObserver::AddUser(Profile* profile) {
259 if (chrome::MultiUserWindowManager::GetMultiProfileMode() == 211 if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
260 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) 212 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
261 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile); 213 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
262 controller_->AdditionalUserAddedToSession(profile->GetOriginalProfile()); 214 controller_->AdditionalUserAddedToSession(profile->GetOriginalProfile());
263 } 215 }
264 216
265 ChromeLauncherController::ChromeLauncherController(Profile* profile, 217 ChromeLauncherController::ChromeLauncherController(Profile* profile,
266 ash::ShelfModel* model) 218 ash::ShelfModel* model)
267 : model_(model), 219 : model_(model), profile_(profile) {
268 item_delegate_manager_(NULL),
269 profile_(profile),
270 app_sync_ui_state_(NULL),
271 ignore_persist_pinned_state_change_(false) {
272 if (!profile_) { 220 if (!profile_) {
273 // If no profile was passed, we take the currently active profile and use it 221 // If no profile was passed, we take the currently active profile and use it
274 // as the owner of the current desktop. 222 // as the owner of the current desktop.
275 // Use the original profile as on chromeos we may get a temporary off the 223 // Use the original profile as on chromeos we may get a temporary off the
276 // record profile, unless in guest session (where off the record profile is 224 // record profile, unless in guest session (where off the record profile is
277 // the right one). 225 // the right one).
278 profile_ = ProfileManager::GetActiveUserProfile(); 226 profile_ = ProfileManager::GetActiveUserProfile();
279 if (!profile_->IsGuestSession() && !profile_->IsSystemProfile()) 227 if (!profile_->IsGuestSession() && !profile_->IsSystemProfile())
280 profile_ = profile_->GetOriginalProfile(); 228 profile_ = profile_->GetOriginalProfile();
281 229
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 ash::ShelfItem item = model_->items()[index]; 458 ash::ShelfItem item = model_->items()[index];
511 459
512 if (item.type == ash::TYPE_PLATFORM_APP || 460 if (item.type == ash::TYPE_PLATFORM_APP ||
513 item.type == ash::TYPE_WINDOWED_APP) { 461 item.type == ash::TYPE_WINDOWED_APP) {
514 item.type = ash::TYPE_APP_SHORTCUT; 462 item.type = ash::TYPE_APP_SHORTCUT;
515 model_->Set(index, item); 463 model_->Set(index, item);
516 } else if (item.type != ash::TYPE_APP_SHORTCUT) { 464 } else if (item.type != ash::TYPE_APP_SHORTCUT) {
517 return; 465 return;
518 } 466 }
519 467
520 if (GetLauncherItemController(id)->CanPin()) 468 UpdatePinnedPosition(id);
521 PersistPinnedState();
522 } 469 }
523 470
524 void ChromeLauncherController::Unpin(ash::ShelfID id) { 471 void ChromeLauncherController::Unpin(ash::ShelfID id) {
525 LauncherItemController* controller = GetLauncherItemController(id); 472 LauncherItemController* controller = GetLauncherItemController(id);
526 CHECK(controller); 473 CHECK(controller);
527 const bool can_pin = controller->CanPin(); 474
475 ash::RemovePinPosition(profile_, GetAppIDForShelfID(id));
528 476
529 if (controller->type() == LauncherItemController::TYPE_APP || 477 if (controller->type() == LauncherItemController::TYPE_APP ||
530 controller->locked()) { 478 controller->locked()) {
531 UnpinRunningAppInternal(model_->ItemIndexByID(id)); 479 UnpinRunningAppInternal(model_->ItemIndexByID(id));
532 } else { 480 } else {
533 LauncherItemClosed(id); 481 LauncherItemClosed(id);
534 } 482 }
535 if (can_pin)
536 PersistPinnedState();
537 } 483 }
538 484
539 bool ChromeLauncherController::IsPinned(ash::ShelfID id) { 485 bool ChromeLauncherController::IsPinned(ash::ShelfID id) {
540 int index = model_->ItemIndexByID(id); 486 int index = model_->ItemIndexByID(id);
541 if (index < 0) 487 if (index < 0)
542 return false; 488 return false;
543 ash::ShelfItemType type = model_->items()[index].type; 489 ash::ShelfItemType type = model_->items()[index].type;
544 return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT); 490 return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT);
545 } 491 }
546 492
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 void ChromeLauncherController::CreateNewWindow() { 724 void ChromeLauncherController::CreateNewWindow() {
779 // Use the currently active user. 725 // Use the currently active user.
780 chrome::NewEmptyWindow(profile_); 726 chrome::NewEmptyWindow(profile_);
781 } 727 }
782 728
783 void ChromeLauncherController::CreateNewIncognitoWindow() { 729 void ChromeLauncherController::CreateNewIncognitoWindow() {
784 // Use the currently active user. 730 // Use the currently active user.
785 chrome::NewEmptyWindow(profile_->GetOffTheRecordProfile()); 731 chrome::NewEmptyWindow(profile_->GetOffTheRecordProfile());
786 } 732 }
787 733
788 void ChromeLauncherController::PersistPinnedState() {
789 if (ignore_persist_pinned_state_change_)
790 return;
791 // It is a coding error to call PersistPinnedState() if the pinned apps are
792 // not user-editable. The code should check earlier and not perform any
793 // modification actions that trigger persisting the state.
794 // Mutating kPinnedLauncherApps is going to notify us and trigger us to
795 // process the change. We don't want that to happen so remove ourselves as a
796 // listener.
797 pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
798 {
799 std::unique_ptr<const base::ListValue> pinned_apps_pref =
800 profile_->GetPrefs()
801 ->GetList(prefs::kPinnedLauncherApps)
802 ->CreateDeepCopy();
803
804 const base::ListValue* policy_pinned_apps_pref =
805 profile_->GetPrefs()->GetList(prefs::kPolicyPinnedLauncherApps);
806
807 ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
808 updater->Clear();
809 for (size_t i = 0; i < model_->items().size(); ++i) {
810 if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
811 ash::ShelfID id = model_->items()[i].id;
812 LauncherItemController* controller = GetLauncherItemController(id);
813 // Don't persist pinning state for apps that are handled internally and
814 // have pinnable state AppListControllerDelegate::NO_PIN.
815 if (controller && IsPinned(id) &&
816 GetPinnable(controller->app_id()) !=
817 AppListControllerDelegate::NO_PIN) {
818 base::DictionaryValue* app_value = ash::CreateAppDict(
819 controller->app_id());
820 if (app_value) {
821 if (!IsAppForUserPinned(controller->app_id(),
822 pinned_apps_pref.get(),
823 policy_pinned_apps_pref))
824 app_value->SetBoolean(ash::kPinnedAppsPrefPinnedByPolicy, true);
825 updater->Append(app_value);
826 }
827 }
828 } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) {
829 PersistChromeItemIndex(i);
830 } else if (model_->items()[i].type == ash::TYPE_APP_LIST) {
831 base::DictionaryValue* app_value =
832 ash::CreateAppDict(ash::kPinnedAppsPlaceholder);
833 if (app_value)
834 updater->Append(app_value);
835 }
836 }
837 }
838 pref_change_registrar_.Add(
839 prefs::kPinnedLauncherApps,
840 base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
841 base::Unretained(this)));
842 }
843
844 Profile* ChromeLauncherController::profile() { 734 Profile* ChromeLauncherController::profile() {
845 return profile_; 735 return profile_;
846 } 736 }
847 737
848 void ChromeLauncherController::UpdateAppState(content::WebContents* contents, 738 void ChromeLauncherController::UpdateAppState(content::WebContents* contents,
849 AppState app_state) { 739 AppState app_state) {
850 std::string app_id = launcher_controller_helper_->GetAppID(contents); 740 std::string app_id = launcher_controller_helper_->GetAppID(contents);
851 741
852 // Check if the gMail app is loaded and it matches the given content. 742 // Check if the gMail app is loaded and it matches the given content.
853 // This special treatment is needed to address crbug.com/234268. 743 // This special treatment is needed to address crbug.com/234268.
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
983 GetDisplayIDForShelf(shelf), 873 GetDisplayIDForShelf(shelf),
984 shelf->auto_hide_behavior()); 874 shelf->auto_hide_behavior());
985 } 875 }
986 876
987 void ChromeLauncherController::OnShelfAutoHideStateChanged(ash::Shelf* shelf) {} 877 void ChromeLauncherController::OnShelfAutoHideStateChanged(ash::Shelf* shelf) {}
988 878
989 void ChromeLauncherController::OnShelfVisibilityStateChanged( 879 void ChromeLauncherController::OnShelfVisibilityStateChanged(
990 ash::Shelf* shelf) {} 880 ash::Shelf* shelf) {}
991 881
992 void ChromeLauncherController::ShelfItemAdded(int index) { 882 void ChromeLauncherController::ShelfItemAdded(int index) {
993 // The app list launcher can get added to the shelf after we applied the
994 // preferences. In that case the item might be at the wrong spot. As such we
995 // call the function again.
996 if (model_->items()[index].type == ash::TYPE_APP_LIST)
997 UpdateAppLaunchersFromPref();
998 } 883 }
999 884
1000 void ChromeLauncherController::ShelfItemRemoved(int index, ash::ShelfID id) { 885 void ChromeLauncherController::ShelfItemRemoved(int index, ash::ShelfID id) {
1001 // TODO(skuhne): This fixes crbug.com/429870, but it does not answer why we 886 // TODO(skuhne): This fixes crbug.com/429870, but it does not answer why we
1002 // get into this state in the first place. 887 // get into this state in the first place.
1003 IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id); 888 IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
1004 if (iter == id_to_item_controller_map_.end()) 889 if (iter == id_to_item_controller_map_.end())
1005 return; 890 return;
1006 891
1007 LOG(ERROR) << "Unexpected change of shelf item id: " << id; 892 LOG(ERROR) << "Unexpected change of shelf item id: " << id;
1008 893
1009 id_to_item_controller_map_.erase(iter); 894 id_to_item_controller_map_.erase(iter);
1010 } 895 }
1011 896
1012 void ChromeLauncherController::ShelfItemMoved(int start_index, 897 void ChromeLauncherController::ShelfItemMoved(int start_index,
1013 int target_index) { 898 int target_index) {
1014 const ash::ShelfItem& item = model_->items()[target_index]; 899 const ash::ShelfItem& item = model_->items()[target_index];
1015 // We remember the moved item position if it is either pinnable or 900 // We remember the moved item position if it is either pinnable or
1016 // it is the app list with the alternate shelf layout. 901 // it is the app list with the alternate shelf layout.
1017 if ((HasShelfIDToAppIDMapping(item.id) && IsPinned(item.id)) || 902 DCHECK_NE(ash::TYPE_APP_LIST, item.type);
1018 item.type == ash::TYPE_APP_LIST) 903 if (HasShelfIDToAppIDMapping(item.id) && IsPinned(item.id))
1019 PersistPinnedState(); 904 UpdatePinnedPosition(item.id);
1020 } 905 }
1021 906
1022 void ChromeLauncherController::ShelfItemChanged( 907 void ChromeLauncherController::ShelfItemChanged(
1023 int index, 908 int index,
1024 const ash::ShelfItem& old_item) {} 909 const ash::ShelfItem& old_item) {}
1025 910
1026 void ChromeLauncherController::ActiveUserChanged( 911 void ChromeLauncherController::ActiveUserChanged(
1027 const std::string& user_email) { 912 const std::string& user_email) {
1028 // Store the order of running applications for the user which gets inactive. 913 // Store the order of running applications for the user which gets inactive.
1029 RememberUnpinnedRunningApplicationOrder(); 914 RememberUnpinnedRunningApplicationOrder();
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
1380 if (IsAppPinned(app_id)) 1265 if (IsAppPinned(app_id))
1381 return; 1266 return;
1382 1267
1383 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id); 1268 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id);
1384 if (shelf_id) { 1269 if (shelf_id) {
1385 // App item exists, pin it 1270 // App item exists, pin it
1386 Pin(shelf_id); 1271 Pin(shelf_id);
1387 } else { 1272 } else {
1388 // Otherwise, create a shortcut item for it. 1273 // Otherwise, create a shortcut item for it.
1389 shelf_id = CreateAppShortcutLauncherItem(app_id, model_->item_count()); 1274 shelf_id = CreateAppShortcutLauncherItem(app_id, model_->item_count());
1390 if (GetPinnable(app_id) == AppListControllerDelegate::PIN_EDITABLE) 1275 UpdatePinnedPosition(shelf_id);
1391 PersistPinnedState();
1392 } 1276 }
1393 } 1277 }
1394 1278
1395 void ChromeLauncherController::DoUnpinAppWithID(const std::string& app_id) { 1279 void ChromeLauncherController::DoUnpinAppWithID(const std::string& app_id) {
1396 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id); 1280 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id);
1397 if (shelf_id && IsPinned(shelf_id)) 1281 if (shelf_id && IsPinned(shelf_id))
1398 Unpin(shelf_id); 1282 Unpin(shelf_id);
1399 } 1283 }
1400 1284
1401 int ChromeLauncherController::PinRunningAppInternal(int index, 1285 int ChromeLauncherController::PinRunningAppInternal(int index,
(...skipping 20 matching lines...) Expand all
1422 DCHECK_EQ(item.type, ash::TYPE_APP_SHORTCUT); 1306 DCHECK_EQ(item.type, ash::TYPE_APP_SHORTCUT);
1423 item.type = ash::TYPE_WINDOWED_APP; 1307 item.type = ash::TYPE_WINDOWED_APP;
1424 // A platform app and a windowed app are sharing TYPE_APP_SHORTCUT. As such 1308 // A platform app and a windowed app are sharing TYPE_APP_SHORTCUT. As such
1425 // we have to check here what this was before it got a shortcut. 1309 // we have to check here what this was before it got a shortcut.
1426 LauncherItemController* controller = GetLauncherItemController(item.id); 1310 LauncherItemController* controller = GetLauncherItemController(item.id);
1427 if (controller && controller->type() == LauncherItemController::TYPE_APP) 1311 if (controller && controller->type() == LauncherItemController::TYPE_APP)
1428 item.type = ash::TYPE_PLATFORM_APP; 1312 item.type = ash::TYPE_PLATFORM_APP;
1429 model_->Set(index, item); 1313 model_->Set(index, item);
1430 } 1314 }
1431 1315
1316 void ChromeLauncherController::UpdatePinnedPosition(ash::ShelfID shelf_id) {
1317 DCHECK(shelf_id);
1318 if (ignore_persist_pinned_state_change_)
1319 return;
1320
1321 const int max_index = model_->item_count();
1322 const int index = model_->ItemIndexByID(shelf_id);
1323 DCHECK_GT(index, 0);
1324
1325 const std::string& app_id = GetAppIDForShelfID(shelf_id);
1326 DCHECK(!app_id.empty());
1327
1328 std::string app_id_before;
1329 std::string app_id_after;
1330
1331 for (int i = index - 1; i > 0; --i) {
1332 const ash::ShelfID shelf_id_before = model_->items()[i].id;
1333 if (IsPinned(shelf_id_before)) {
1334 app_id_before = GetAppIDForShelfID(shelf_id_before);
1335 DCHECK(!app_id_before.empty());
1336 break;
1337 }
1338 }
1339
1340 for (int i = index + 1; i < max_index; ++i) {
1341 const ash::ShelfID shelf_id_after = model_->items()[i].id;
1342 if (IsPinned(shelf_id_after)) {
1343 app_id_after = GetAppIDForShelfID(shelf_id_after);
1344 DCHECK(!app_id_after.empty());
1345 break;
1346 }
1347 }
1348
1349 ash::SetPinPosition(profile_, app_id, app_id_before, app_id_after);
1350 }
1351
1352 void ChromeLauncherController::OnSyncModelUpdated() {
1353 UpdateAppLaunchersFromPref();
1354 }
1355
1432 void ChromeLauncherController::UpdateAppLaunchersFromPref() { 1356 void ChromeLauncherController::UpdateAppLaunchersFromPref() {
1433 // There are various functions which will trigger a |PersistPinnedState| call 1357 // There are various functions which will trigger a |UpdatePinnedPosition|
1434 // like a direct call to |DoPinAppWithID|, or an indirect call to the menu 1358 // call like a direct call to |DoPinAppWithID|, or an indirect call to the
1435 // model which will use weights to re-arrange the icons to new positions. 1359 // menu model which will use weights to re-arrange the icons to new positions.
1436 // Since this function is meant to synchronize the "is state" with the 1360 // Since this function is meant to synchronize the "is state" with the
1437 // "sync state", it makes no sense to store any changes by this function back 1361 // "sync state", it makes no sense to store any changes by this function back
1438 // into the pref state. Therefore we tell |persistPinnedState| to ignore any 1362 // into the pref state. Therefore we tell |persistPinnedState| to ignore any
1439 // invocations while we are running. 1363 // invocations while we are running.
1440 base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true); 1364 base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true);
1365
1441 std::vector<std::string> pinned_apps = ash::GetPinnedAppsFromPrefs( 1366 std::vector<std::string> pinned_apps = ash::GetPinnedAppsFromPrefs(
1442 profile_->GetPrefs(), launcher_controller_helper_.get()); 1367 profile_->GetPrefs(), launcher_controller_helper_.get());
1443 1368
1444 int index = 0; 1369 int index = 1;
1445 int max_index = model_->item_count(); 1370 int max_index = model_->item_count();
1371 int seen_chrome_index = -1;
1446 1372
1447 // When one of the two special items cannot be moved (and we do not know where 1373 // At least chrome browser shortcut should exist.
1448 // yet), we remember the current location in one of these variables. 1374 DCHECK_GT(max_index, 0);
1449 int chrome_index = -1; 1375 DCHECK_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
1450 int app_list_index = -1;
1451 1376
1452 // Walk the model and |pinned_apps| from the pref lockstep, adding and 1377 // Walk the model and |pinned_apps| from the pref lockstep, adding and
1453 // removing items as necessary. NB: This code uses plain old indexing instead 1378 // removing items as necessary. NB: This code uses plain old indexing instead
1454 // of iterators because of model mutations as part of the loop. 1379 // of iterators because of model mutations as part of the loop.
1455 std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin()); 1380 std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
1456 for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) { 1381 for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
1457 // Check if we have an item which we need to handle. 1382 // Check if we have an item which we need to handle.
1458 if (*pref_app_id == extension_misc::kChromeAppId || 1383 if (IsAppPinned(*pref_app_id)) {
1459 *pref_app_id == ash::kPinnedAppsPlaceholder || 1384 if (seen_chrome_index >= 0 &&
1460 IsAppPinned(*pref_app_id)) { 1385 *pref_app_id == extension_misc::kChromeAppId) {
1386 // Current item is Chrome browser and we saw it before.
1387 model_->Move(seen_chrome_index, index);
1388 ++pref_app_id;
1389 --index;
1390 continue;
1391 }
1461 for (; index < max_index; ++index) { 1392 for (; index < max_index; ++index) {
1462 const ash::ShelfItem& item(model_->items()[index]); 1393 const ash::ShelfItem& item(model_->items()[index]);
1463 bool is_app_list = item.type == ash::TYPE_APP_LIST; 1394 if (item.type != ash::TYPE_APP_SHORTCUT &&
1464 bool is_chrome = item.type == ash::TYPE_BROWSER_SHORTCUT; 1395 item.type != ash::TYPE_BROWSER_SHORTCUT)
1465 if (item.type != ash::TYPE_APP_SHORTCUT && !is_app_list && !is_chrome)
1466 continue; 1396 continue;
1467 LauncherItemController* controller = GetLauncherItemController(item.id); 1397 LauncherItemController* controller = GetLauncherItemController(item.id);
1468 if ((ash::kPinnedAppsPlaceholder == *pref_app_id && is_app_list) || 1398 if (controller && controller->app_id() == *pref_app_id) {
1469 (extension_misc::kChromeAppId == *pref_app_id && is_chrome) ||
1470 (controller && controller->app_id() == *pref_app_id)) {
1471 // Check if an item needs to be moved here.
1472 MoveChromeOrApplistToFinalPosition(
1473 is_chrome, is_app_list, index, &chrome_index, &app_list_index);
1474 ++pref_app_id; 1399 ++pref_app_id;
1475 break; 1400 break;
1401 } else if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
1402 // We cannot close browser shortcut. Remember its position.
1403 seen_chrome_index = index;
1476 } else { 1404 } else {
1477 if (is_chrome || is_app_list) { 1405 // Check if this is a platform or a windowed app.
1478 // We cannot delete any of these shortcuts. As such we remember 1406 if (item.type == ash::TYPE_APP_SHORTCUT && controller &&
1479 // their positions and move them later where they belong. 1407 (controller->locked() ||
1480 if (is_chrome) 1408 controller->type() == LauncherItemController::TYPE_APP)) {
1481 chrome_index = index; 1409 // Note: This will not change the amount of items (|max_index|).
1482 else 1410 // Even changes to the actual |index| due to item weighting
1483 app_list_index = index; 1411 // changes should be fine.
1484 // And skip the item - or exit the loop if end is reached (note that 1412 UnpinRunningAppInternal(index);
1485 // in that case we will reduce the index again by one and this only
1486 // compensates for it).
1487 if (index >= max_index - 1)
1488 break;
1489 ++index;
1490 } else { 1413 } else {
1491 // Check if this is a platform or a windowed app. 1414 if (controller)
1492 if (item.type == ash::TYPE_APP_SHORTCUT && 1415 LauncherItemClosed(item.id);
1493 controller && 1416 --max_index;
1494 (controller->locked() ||
1495 controller->type() == LauncherItemController::TYPE_APP)) {
1496 // Note: This will not change the amount of items (|max_index|).
1497 // Even changes to the actual |index| due to item weighting
1498 // changes should be fine.
1499 UnpinRunningAppInternal(index);
1500 } else {
1501 if (controller)
1502 LauncherItemClosed(item.id);
1503 --max_index;
1504 }
1505 } 1417 }
1506 --index; 1418 --index;
1507 } 1419 }
1508 } 1420 }
1509 // If the item wasn't found, that means id_to_item_controller_map_ 1421 // If the item wasn't found, that means id_to_item_controller_map_
1510 // is out of sync. 1422 // is out of sync.
1511 DCHECK(index <= max_index); 1423 DCHECK(index <= max_index);
1512 } else { 1424 } else {
1513 // Check if the item was already running but not yet pinned. 1425 // Check if the item was already running but not yet pinned.
1514 ash::ShelfID shelf_id = GetShelfIDForAppID(*pref_app_id); 1426 ash::ShelfID shelf_id = GetShelfIDForAppID(*pref_app_id);
(...skipping 17 matching lines...) Expand all
1532 LauncherItemController* controller = GetLauncherItemController(item.id); 1444 LauncherItemController* controller = GetLauncherItemController(item.id);
1533 if (controller) { 1445 if (controller) {
1534 if (controller->locked() || 1446 if (controller->locked() ||
1535 controller->type() == LauncherItemController::TYPE_APP) { 1447 controller->type() == LauncherItemController::TYPE_APP) {
1536 UnpinRunningAppInternal(index); 1448 UnpinRunningAppInternal(index);
1537 } else { 1449 } else {
1538 LauncherItemClosed(item.id); 1450 LauncherItemClosed(item.id);
1539 } 1451 }
1540 } 1452 }
1541 } else { 1453 } else {
1542 if (item.type == ash::TYPE_BROWSER_SHORTCUT)
1543 chrome_index = index;
1544 else if (item.type == ash::TYPE_APP_LIST)
1545 app_list_index = index;
1546 ++index; 1454 ++index;
1547 } 1455 }
1548 } 1456 }
1549 1457
1550 // Append unprocessed items from the pref to the end of the model. 1458 // Append unprocessed items from the pref to the end of the model.
1551 for (; pref_app_id != pinned_apps.end(); ++pref_app_id) { 1459 for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
1552 // All items but the chrome and / or app list shortcut needs to be added. 1460 if (*pref_app_id == extension_misc::kChromeAppId) {
1553 bool is_chrome = *pref_app_id == extension_misc::kChromeAppId; 1461 int target_index = FindInsertionPoint();
1554 bool is_app_list = *pref_app_id == ash::kPinnedAppsPlaceholder; 1462 DCHECK(seen_chrome_index >= 0 && seen_chrome_index < target_index);
1555 // Coming here we know the next item which can be finalized, either the 1463 model_->Move(seen_chrome_index, target_index);
1556 // chrome item or the app launcher. The final position is the end of the 1464 } else {
1557 // list. The menu model will make sure that the item is grouped according
1558 // to its weight (which we do not know here).
1559 if (!is_chrome && !is_app_list) {
1560 DoPinAppWithID(*pref_app_id); 1465 DoPinAppWithID(*pref_app_id);
1561 int target_index = FindInsertionPoint(false); 1466 int target_index = FindInsertionPoint();
1562 ash::ShelfID id = GetShelfIDForAppID(*pref_app_id); 1467 ash::ShelfID id = GetShelfIDForAppID(*pref_app_id);
1563 int source_index = model_->ItemIndexByID(id); 1468 int source_index = model_->ItemIndexByID(id);
1564 if (source_index != target_index) 1469 if (source_index != target_index)
1565 model_->Move(source_index, target_index); 1470 model_->Move(source_index, target_index);
1566
1567 // Needed for the old layout - the weight might force it to be lower in
1568 // rank.
1569 if (app_list_index != -1 && target_index <= app_list_index)
1570 ++app_list_index;
1571 } else {
1572 int target_index = FindInsertionPoint(is_app_list);
1573 MoveChromeOrApplistToFinalPosition(
1574 is_chrome, is_app_list, target_index, &chrome_index, &app_list_index);
1575 } 1471 }
1576 } 1472 }
1577 } 1473 }
1578 1474
1579 void ChromeLauncherController::SetShelfAutoHideBehaviorFromPrefs() { 1475 void ChromeLauncherController::SetShelfAutoHideBehaviorFromPrefs() {
1580 for (auto* window : ash::Shell::GetAllRootWindows()) { 1476 for (auto* window : ash::Shell::GetAllRootWindows()) {
1581 ash::Shelf* shelf = ash::Shelf::ForWindow(window); 1477 ash::Shelf* shelf = ash::Shelf::ForWindow(window);
1582 if (shelf) { 1478 if (shelf) {
1583 shelf->SetAutoHideBehavior(ash::GetShelfAutoHideBehaviorPref( 1479 shelf->SetAutoHideBehavior(ash::GetShelfAutoHideBehaviorPref(
1584 profile_->GetPrefs(), GetDisplayIDForShelf(shelf))); 1480 profile_->GetPrefs(), GetDisplayIDForShelf(shelf)));
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1704 << "There should be always be a BrowserShortcutLauncherItemController."; 1600 << "There should be always be a BrowserShortcutLauncherItemController.";
1705 return nullptr; 1601 return nullptr;
1706 } 1602 }
1707 1603
1708 ash::ShelfID ChromeLauncherController::CreateBrowserShortcutLauncherItem() { 1604 ash::ShelfID ChromeLauncherController::CreateBrowserShortcutLauncherItem() {
1709 ash::ShelfItem browser_shortcut; 1605 ash::ShelfItem browser_shortcut;
1710 browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT; 1606 browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT;
1711 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 1607 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1712 browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32); 1608 browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
1713 ash::ShelfID id = model_->next_id(); 1609 ash::ShelfID id = model_->next_id();
1714 size_t index = GetChromeIconIndexForCreation(); 1610 model_->AddAt(0, browser_shortcut);
1715 model_->AddAt(index, browser_shortcut);
1716 id_to_item_controller_map_[id] = 1611 id_to_item_controller_map_[id] =
1717 new BrowserShortcutLauncherItemController(this, model_); 1612 new BrowserShortcutLauncherItemController(this, model_);
1718 id_to_item_controller_map_[id]->set_shelf_id(id); 1613 id_to_item_controller_map_[id]->set_shelf_id(id);
1719 // ShelfItemDelegateManager owns BrowserShortcutLauncherItemController. 1614 // ShelfItemDelegateManager owns BrowserShortcutLauncherItemController.
1720 SetShelfItemDelegate(id, id_to_item_controller_map_[id]); 1615 SetShelfItemDelegate(id, id_to_item_controller_map_[id]);
1721 return id; 1616 return id;
1722 } 1617 }
1723 1618
1724 void ChromeLauncherController::PersistChromeItemIndex(int index) { 1619 int ChromeLauncherController::FindInsertionPoint() {
1725 profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index); 1620 DCHECK_GT(model_->item_count(), 0);
1726 }
1727
1728 void ChromeLauncherController::MoveChromeOrApplistToFinalPosition(
1729 bool is_chrome,
1730 bool is_app_list,
1731 int target_index,
1732 int* chrome_index,
1733 int* app_list_index) {
1734 if (is_chrome && *chrome_index != -1) {
1735 model_->Move(*chrome_index, target_index);
1736 if (*app_list_index != -1 &&
1737 *chrome_index < *app_list_index &&
1738 target_index > *app_list_index)
1739 --(*app_list_index);
1740 *chrome_index = -1;
1741 } else if (is_app_list && *app_list_index != -1) {
1742 model_->Move(*app_list_index, target_index);
1743 if (*chrome_index != -1 &&
1744 *app_list_index < *chrome_index &&
1745 target_index > *chrome_index)
1746 --(*chrome_index);
1747 *app_list_index = -1;
1748 }
1749 }
1750
1751 int ChromeLauncherController::FindInsertionPoint(bool is_app_list) {
1752 // Keeping this change small to backport to M33&32 (see crbug.com/329597).
1753 // TODO(skuhne): With the removal of the legacy shelf layout we should remove
1754 // the ability to move the app list item since this was never used. We should
1755 // instead ask the ShelfModel::ValidateInsertionIndex or similir for an index.
1756 if (is_app_list)
1757 return 0;
1758 1621
1759 for (int i = model_->item_count() - 1; i > 0; --i) { 1622 for (int i = model_->item_count() - 1; i > 0; --i) {
1760 ash::ShelfItemType type = model_->items()[i].type; 1623 ash::ShelfItemType type = model_->items()[i].type;
1624 DCHECK_NE(ash::TYPE_APP_LIST, type);
1761 if (type == ash::TYPE_APP_SHORTCUT || 1625 if (type == ash::TYPE_APP_SHORTCUT ||
1762 (is_app_list && type == ash::TYPE_APP_LIST) ||
1763 type == ash::TYPE_BROWSER_SHORTCUT) { 1626 type == ash::TYPE_BROWSER_SHORTCUT) {
1764 return i; 1627 return i;
1765 } 1628 }
1766 } 1629 }
1767 return 0; 1630 return 0;
1768 } 1631 }
1769 1632
1770 int ChromeLauncherController::GetChromeIconIndexForCreation() {
1771 // We get the list of pinned apps as they currently would get pinned.
1772 // Within this list the chrome icon will be the correct location.
1773 std::vector<std::string> pinned_apps = ash::GetPinnedAppsFromPrefs(
1774 profile_->GetPrefs(), launcher_controller_helper_.get());
1775
1776 std::vector<std::string>::iterator it =
1777 std::find(pinned_apps.begin(),
1778 pinned_apps.end(),
1779 std::string(extension_misc::kChromeAppId));
1780 DCHECK(it != pinned_apps.end());
1781 int index = it - pinned_apps.begin();
1782
1783 // We should do here a comparison between the is state and the "want to be"
1784 // state since some apps might be able to pin but are not yet. Instead - for
1785 // the time being we clamp against the amount of known items and wait for the
1786 // next |UpdateAppLaunchersFromPref()| call to correct it - it will come since
1787 // the pinning will be done then.
1788 return std::min(model_->item_count(), index);
1789 }
1790
1791 bool ChromeLauncherController::IsIncognito( 1633 bool ChromeLauncherController::IsIncognito(
1792 const content::WebContents* web_contents) const { 1634 const content::WebContents* web_contents) const {
1793 const Profile* profile = 1635 const Profile* profile =
1794 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 1636 Profile::FromBrowserContext(web_contents->GetBrowserContext());
1795 return profile->IsOffTheRecord() && !profile->IsGuestSession() && 1637 return profile->IsOffTheRecord() && !profile->IsGuestSession() &&
1796 !profile->IsSystemProfile(); 1638 !profile->IsSystemProfile();
1797 } 1639 }
1798 1640
1799 void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension( 1641 void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension(
1800 const std::string& app_id, 1642 const std::string& app_id,
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1853 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) { 1695 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) {
1854 DCHECK(arc_deferred_launcher()); 1696 DCHECK(arc_deferred_launcher());
1855 std::unique_ptr<AppIconLoader> arc_app_icon_loader( 1697 std::unique_ptr<AppIconLoader> arc_app_icon_loader(
1856 new ArcAppIconLoader(profile_, extension_misc::EXTENSION_ICON_SMALL, 1698 new ArcAppIconLoader(profile_, extension_misc::EXTENSION_ICON_SMALL,
1857 arc_deferred_launcher(), this)); 1699 arc_deferred_launcher(), this));
1858 app_icon_loaders_.push_back(std::move(arc_app_icon_loader)); 1700 app_icon_loaders_.push_back(std::move(arc_app_icon_loader));
1859 } 1701 }
1860 1702
1861 pref_change_registrar_.Init(profile_->GetPrefs()); 1703 pref_change_registrar_.Init(profile_->GetPrefs());
1862 pref_change_registrar_.Add( 1704 pref_change_registrar_.Add(
1863 prefs::kPinnedLauncherApps,
1864 base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
1865 base::Unretained(this)));
1866 pref_change_registrar_.Add(
1867 prefs::kPolicyPinnedLauncherApps, 1705 prefs::kPolicyPinnedLauncherApps,
1868 base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref, 1706 base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
1869 base::Unretained(this))); 1707 base::Unretained(this)));
1870 pref_change_registrar_.Add( 1708 pref_change_registrar_.Add(
1871 prefs::kShelfAlignmentLocal, 1709 prefs::kShelfAlignmentLocal,
1872 base::Bind(&ChromeLauncherController::SetShelfAlignmentFromPrefs, 1710 base::Bind(&ChromeLauncherController::SetShelfAlignmentFromPrefs,
1873 base::Unretained(this))); 1711 base::Unretained(this)));
1874 pref_change_registrar_.Add( 1712 pref_change_registrar_.Add(
1875 prefs::kShelfAutoHideBehaviorLocal, 1713 prefs::kShelfAutoHideBehaviorLocal,
1876 base::Bind(&ChromeLauncherController:: 1714 base::Bind(&ChromeLauncherController::
(...skipping 10 matching lines...) Expand all
1887 1725
1888 std::unique_ptr<LauncherAppUpdater> extension_app_updater( 1726 std::unique_ptr<LauncherAppUpdater> extension_app_updater(
1889 new LauncherExtensionAppUpdater(this, profile_)); 1727 new LauncherExtensionAppUpdater(this, profile_));
1890 app_updaters_.push_back(std::move(extension_app_updater)); 1728 app_updaters_.push_back(std::move(extension_app_updater));
1891 1729
1892 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) { 1730 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) {
1893 std::unique_ptr<LauncherAppUpdater> arc_app_updater( 1731 std::unique_ptr<LauncherAppUpdater> arc_app_updater(
1894 new LauncherArcAppUpdater(this, profile_)); 1732 new LauncherArcAppUpdater(this, profile_));
1895 app_updaters_.push_back(std::move(arc_app_updater)); 1733 app_updaters_.push_back(std::move(arc_app_updater));
1896 } 1734 }
1735
1736 app_list::AppListSyncableService* app_service =
1737 app_list::AppListSyncableService::Get(profile_);
1738 if (app_service)
1739 app_service->AddObserverAndStart(this);
1897 } 1740 }
1898 1741
1899 void ChromeLauncherController::ReleaseProfile() { 1742 void ChromeLauncherController::ReleaseProfile() {
1900 if (app_sync_ui_state_) 1743 if (app_sync_ui_state_)
1901 app_sync_ui_state_->RemoveObserver(this); 1744 app_sync_ui_state_->RemoveObserver(this);
1902 1745
1903 app_updaters_.clear(); 1746 app_updaters_.clear();
1904 1747
1905 PrefServiceSyncableFromProfile(profile_)->RemoveObserver(this); 1748 PrefServiceSyncableFromProfile(profile_)->RemoveObserver(this);
1906 1749
1907 pref_change_registrar_.RemoveAll(); 1750 pref_change_registrar_.RemoveAll();
1751
1752 app_list::AppListSyncableService* app_service =
1753 app_list::AppListSyncableService::Get(profile_);
1754 if (app_service)
1755 app_service->RemoveObserver(this);
1908 } 1756 }
1909 1757
1910 AppIconLoader* ChromeLauncherController::GetAppIconLoaderForApp( 1758 AppIconLoader* ChromeLauncherController::GetAppIconLoaderForApp(
1911 const std::string& app_id) { 1759 const std::string& app_id) {
1912 for (const auto& app_icon_loader : app_icon_loaders_) { 1760 for (const auto& app_icon_loader : app_icon_loaders_) {
1913 if (app_icon_loader->CanLoadImageForApp(app_id)) 1761 if (app_icon_loader->CanLoadImageForApp(app_id))
1914 return app_icon_loader.get(); 1762 return app_icon_loader.get();
1915 } 1763 }
1916 1764
1917 return nullptr; 1765 return nullptr;
1918 } 1766 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698