| OLD | NEW |
| 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_impl.h" | 5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "ash/wm/window_util.h" | 21 #include "ash/wm/window_util.h" |
| 22 #include "base/command_line.h" | 22 #include "base/command_line.h" |
| 23 #include "base/macros.h" | 23 #include "base/macros.h" |
| 24 #include "base/strings/pattern.h" | 24 #include "base/strings/pattern.h" |
| 25 #include "base/strings/string_util.h" | 25 #include "base/strings/string_util.h" |
| 26 #include "base/strings/utf_string_conversions.h" | 26 #include "base/strings/utf_string_conversions.h" |
| 27 #include "base/values.h" | 27 #include "base/values.h" |
| 28 #include "build/build_config.h" | 28 #include "build/build_config.h" |
| 29 #include "chrome/browser/browser_process.h" | 29 #include "chrome/browser/browser_process.h" |
| 30 #include "chrome/browser/chrome_notification_types.h" | 30 #include "chrome/browser/chrome_notification_types.h" |
| 31 #include "chrome/browser/chromeos/arc/arc_support_host.h" | |
| 32 #include "chrome/browser/chromeos/extensions/gfx_utils.h" | 31 #include "chrome/browser/chromeos/extensions/gfx_utils.h" |
| 33 #include "chrome/browser/defaults.h" | 32 #include "chrome/browser/defaults.h" |
| 34 #include "chrome/browser/extensions/extension_app_icon_loader.h" | 33 #include "chrome/browser/extensions/extension_app_icon_loader.h" |
| 35 #include "chrome/browser/extensions/extension_util.h" | 34 #include "chrome/browser/extensions/extension_util.h" |
| 36 #include "chrome/browser/extensions/launch_util.h" | 35 #include "chrome/browser/extensions/launch_util.h" |
| 37 #include "chrome/browser/prefs/incognito_mode_prefs.h" | 36 #include "chrome/browser/prefs/incognito_mode_prefs.h" |
| 38 #include "chrome/browser/profiles/profile.h" | 37 #include "chrome/browser/profiles/profile.h" |
| 39 #include "chrome/browser/profiles/profile_manager.h" | 38 #include "chrome/browser/profiles/profile_manager.h" |
| 39 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" |
| 40 #include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h" | 40 #include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h" |
| 41 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" | 41 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" |
| 42 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" | 42 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" |
| 43 #include "chrome/browser/ui/ash/app_sync_ui_state.h" | 43 #include "chrome/browser/ui/ash/app_sync_ui_state.h" |
| 44 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h" | 44 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h" |
| 45 #include "chrome/browser/ui/ash/chrome_shell_delegate.h" | 45 #include "chrome/browser/ui/ash/chrome_shell_delegate.h" |
| 46 #include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
" | 46 #include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
" |
| 47 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h" | 47 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h" |
| 48 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h" | 48 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h" |
| 49 #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h" | 49 #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 | 110 |
| 111 int64_t GetDisplayIDForShelf(ash::Shelf* shelf) { | 111 int64_t GetDisplayIDForShelf(ash::Shelf* shelf) { |
| 112 aura::Window* root_window = | 112 aura::Window* root_window = |
| 113 shelf->shelf_widget()->GetNativeWindow()->GetRootWindow(); | 113 shelf->shelf_widget()->GetNativeWindow()->GetRootWindow(); |
| 114 display::Display display = | 114 display::Display display = |
| 115 display::Screen::GetScreen()->GetDisplayNearestWindow(root_window); | 115 display::Screen::GetScreen()->GetDisplayNearestWindow(root_window); |
| 116 DCHECK(display.is_valid()); | 116 DCHECK(display.is_valid()); |
| 117 return display.id(); | 117 return display.id(); |
| 118 } | 118 } |
| 119 | 119 |
| 120 /* | |
| 121 * Return whether an app is pinned only by user. | |
| 122 * This function doesn't expect an app_id neither pinned by user nor by | |
| 123 * policy, the app_id in the arguments list MUST be pinned by either of | |
| 124 * those. Invalid input may lead to unexpected result. | |
| 125 * If this app is pinned by policy, but not by user, false is returned. | |
| 126 * If this app is pinned by both policy and user, false is returned. | |
| 127 * If this app is pinned not by policy, but by user, true is returned. | |
| 128 */ | |
| 129 bool IsAppForUserPinned(const std::string& app_id, | |
| 130 const base::ListValue* pinned_apps_pref, | |
| 131 const base::ListValue* policy_pinned_apps_pref) { | |
| 132 for (size_t index = 0; index < pinned_apps_pref->GetSize(); ++index) { | |
| 133 const base::DictionaryValue* app; | |
| 134 if (pinned_apps_pref->GetDictionary(index, &app)) { | |
| 135 std::string current_app_id; | |
| 136 bool pinned_by_policy = false; | |
| 137 if (app->GetString(ash::kPinnedAppsPrefAppIDPath, ¤t_app_id)) { | |
| 138 if (app_id == current_app_id) { | |
| 139 if (app->GetBoolean(ash::kPinnedAppsPrefPinnedByPolicy, | |
| 140 &pinned_by_policy) && | |
| 141 pinned_by_policy) { | |
| 142 // Pinned by policy in the past or present. | |
| 143 // Need to check policy_pinned_apps to determine | |
| 144 break; | |
| 145 } else { | |
| 146 // User Preference Already Pinned | |
| 147 return true; | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 } | |
| 152 } | |
| 153 for (size_t index = 0; index < policy_pinned_apps_pref->GetSize(); ++index) { | |
| 154 const base::DictionaryValue* app; | |
| 155 if (policy_pinned_apps_pref->GetDictionary(index, &app)) { | |
| 156 std::string app_id_; | |
| 157 if (app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id_)) { | |
| 158 // Only pinned by policy, which is not part of user-pinned | |
| 159 if (app_id == app_id_) | |
| 160 return false; | |
| 161 } | |
| 162 } | |
| 163 } | |
| 164 // Default, user added new pins | |
| 165 return true; | |
| 166 } | |
| 167 | |
| 168 const char* const kPinProhibitedExtensionIds[] = { | |
| 169 ArcSupportHost::kHostAppId, arc::kPlayStoreAppId, | |
| 170 }; | |
| 171 | |
| 172 const size_t kPinProhibitedExtensionIdsLength = | |
| 173 arraysize(kPinProhibitedExtensionIds); | |
| 174 | |
| 175 } // namespace | 120 } // namespace |
| 176 | 121 |
| 177 // A class to get events from ChromeOS when a user gets changed or added. | 122 // A class to get events from ChromeOS when a user gets changed or added. |
| 178 class ChromeLauncherControllerUserSwitchObserver | 123 class ChromeLauncherControllerUserSwitchObserver |
| 179 : public user_manager::UserManager::UserSessionStateObserver { | 124 : public user_manager::UserManager::UserSessionStateObserver { |
| 180 public: | 125 public: |
| 181 ChromeLauncherControllerUserSwitchObserver( | 126 ChromeLauncherControllerUserSwitchObserver( |
| 182 ChromeLauncherControllerImpl* controller) | 127 ChromeLauncherControllerImpl* controller) |
| 183 : controller_(controller) { | 128 : controller_(controller) { |
| 184 DCHECK(user_manager::UserManager::IsInitialized()); | 129 DCHECK(user_manager::UserManager::IsInitialized()); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 void ChromeLauncherControllerUserSwitchObserver::AddUser(Profile* profile) { | 184 void ChromeLauncherControllerUserSwitchObserver::AddUser(Profile* profile) { |
| 240 if (chrome::MultiUserWindowManager::GetMultiProfileMode() == | 185 if (chrome::MultiUserWindowManager::GetMultiProfileMode() == |
| 241 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) | 186 chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) |
| 242 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile); | 187 chrome::MultiUserWindowManager::GetInstance()->AddUser(profile); |
| 243 controller_->AdditionalUserAddedToSession(profile->GetOriginalProfile()); | 188 controller_->AdditionalUserAddedToSession(profile->GetOriginalProfile()); |
| 244 } | 189 } |
| 245 | 190 |
| 246 ChromeLauncherControllerImpl::ChromeLauncherControllerImpl( | 191 ChromeLauncherControllerImpl::ChromeLauncherControllerImpl( |
| 247 Profile* profile, | 192 Profile* profile, |
| 248 ash::ShelfModel* model) | 193 ash::ShelfModel* model) |
| 249 : model_(model), | 194 : model_(model), profile_(profile) { |
| 250 item_delegate_manager_(NULL), | |
| 251 profile_(profile), | |
| 252 app_sync_ui_state_(NULL), | |
| 253 ignore_persist_pinned_state_change_(false) { | |
| 254 if (!profile_) { | 195 if (!profile_) { |
| 255 // If no profile was passed, we take the currently active profile and use it | 196 // If no profile was passed, we take the currently active profile and use it |
| 256 // as the owner of the current desktop. | 197 // as the owner of the current desktop. |
| 257 // Use the original profile as on chromeos we may get a temporary off the | 198 // Use the original profile as on chromeos we may get a temporary off the |
| 258 // record profile, unless in guest session (where off the record profile is | 199 // record profile, unless in guest session (where off the record profile is |
| 259 // the right one). | 200 // the right one). |
| 260 profile_ = ProfileManager::GetActiveUserProfile(); | 201 profile_ = ProfileManager::GetActiveUserProfile(); |
| 261 if (!profile_->IsGuestSession() && !profile_->IsSystemProfile()) | 202 if (!profile_->IsGuestSession() && !profile_->IsSystemProfile()) |
| 262 profile_ = profile_->GetOriginalProfile(); | 203 profile_ = profile_->GetOriginalProfile(); |
| 263 | 204 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 | 310 |
| 370 void ChromeLauncherControllerImpl::Init() { | 311 void ChromeLauncherControllerImpl::Init() { |
| 371 CreateBrowserShortcutLauncherItem(); | 312 CreateBrowserShortcutLauncherItem(); |
| 372 UpdateAppLaunchersFromPref(); | 313 UpdateAppLaunchersFromPref(); |
| 373 | 314 |
| 374 // TODO(sky): update unit test so that this test isn't necessary. | 315 // TODO(sky): update unit test so that this test isn't necessary. |
| 375 if (ash::Shell::HasInstance()) | 316 if (ash::Shell::HasInstance()) |
| 376 SetVirtualKeyboardBehaviorFromPrefs(); | 317 SetVirtualKeyboardBehaviorFromPrefs(); |
| 377 | 318 |
| 378 prefs_observer_ = | 319 prefs_observer_ = |
| 379 ash::ChromeLauncherPrefsObserver::CreateIfNecessary(profile_); | 320 ash::launcher::ChromeLauncherPrefsObserver::CreateIfNecessary(profile_); |
| 380 } | 321 } |
| 381 | 322 |
| 382 ash::ShelfID ChromeLauncherControllerImpl::CreateAppLauncherItem( | 323 ash::ShelfID ChromeLauncherControllerImpl::CreateAppLauncherItem( |
| 383 LauncherItemController* controller, | 324 LauncherItemController* controller, |
| 384 const std::string& app_id, | 325 const std::string& app_id, |
| 385 ash::ShelfItemStatus status) { | 326 ash::ShelfItemStatus status) { |
| 386 CHECK(controller); | 327 CHECK(controller); |
| 387 int index = 0; | 328 int index = 0; |
| 388 // Panels are inserted on the left so as not to push all existing panels over. | 329 // Panels are inserted on the left so as not to push all existing panels over. |
| 389 if (controller->GetShelfItemType() != ash::TYPE_APP_PANEL) | 330 if (controller->GetShelfItemType() != ash::TYPE_APP_PANEL) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 ash::ShelfItem item = model_->items()[index]; | 384 ash::ShelfItem item = model_->items()[index]; |
| 444 | 385 |
| 445 if (item.type == ash::TYPE_PLATFORM_APP || | 386 if (item.type == ash::TYPE_PLATFORM_APP || |
| 446 item.type == ash::TYPE_WINDOWED_APP) { | 387 item.type == ash::TYPE_WINDOWED_APP) { |
| 447 item.type = ash::TYPE_APP_SHORTCUT; | 388 item.type = ash::TYPE_APP_SHORTCUT; |
| 448 model_->Set(index, item); | 389 model_->Set(index, item); |
| 449 } else if (item.type != ash::TYPE_APP_SHORTCUT) { | 390 } else if (item.type != ash::TYPE_APP_SHORTCUT) { |
| 450 return; | 391 return; |
| 451 } | 392 } |
| 452 | 393 |
| 453 if (GetLauncherItemController(id)->CanPin()) | 394 SyncPinPosition(id); |
| 454 PersistPinnedState(); | |
| 455 } | 395 } |
| 456 | 396 |
| 457 void ChromeLauncherControllerImpl::Unpin(ash::ShelfID id) { | 397 void ChromeLauncherControllerImpl::Unpin(ash::ShelfID id) { |
| 458 LauncherItemController* controller = GetLauncherItemController(id); | 398 LauncherItemController* controller = GetLauncherItemController(id); |
| 459 CHECK(controller); | 399 CHECK(controller); |
| 460 const bool can_pin = controller->CanPin(); | 400 |
| 401 ash::launcher::RemovePinPosition(profile_, GetAppIDForShelfID(id)); |
| 461 | 402 |
| 462 if (controller->type() == LauncherItemController::TYPE_APP || | 403 if (controller->type() == LauncherItemController::TYPE_APP || |
| 463 controller->locked()) { | 404 controller->locked()) { |
| 464 UnpinRunningAppInternal(model_->ItemIndexByID(id)); | 405 UnpinRunningAppInternal(model_->ItemIndexByID(id)); |
| 465 } else { | 406 } else { |
| 466 LauncherItemClosed(id); | 407 LauncherItemClosed(id); |
| 467 } | 408 } |
| 468 if (can_pin) | |
| 469 PersistPinnedState(); | |
| 470 } | 409 } |
| 471 | 410 |
| 472 bool ChromeLauncherControllerImpl::IsPinned(ash::ShelfID id) { | 411 bool ChromeLauncherControllerImpl::IsPinned(ash::ShelfID id) { |
| 473 int index = model_->ItemIndexByID(id); | 412 int index = model_->ItemIndexByID(id); |
| 474 if (index < 0) | 413 if (index < 0) |
| 475 return false; | 414 return false; |
| 476 ash::ShelfItemType type = model_->items()[index].type; | 415 ash::ShelfItemType type = model_->items()[index].type; |
| 477 return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT); | 416 return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT); |
| 478 } | 417 } |
| 479 | 418 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 void ChromeLauncherControllerImpl::SetLaunchType( | 555 void ChromeLauncherControllerImpl::SetLaunchType( |
| 617 ash::ShelfID id, | 556 ash::ShelfID id, |
| 618 extensions::LaunchType launch_type) { | 557 extensions::LaunchType launch_type) { |
| 619 LauncherItemController* controller = GetLauncherItemController(id); | 558 LauncherItemController* controller = GetLauncherItemController(id); |
| 620 if (!controller) | 559 if (!controller) |
| 621 return; | 560 return; |
| 622 | 561 |
| 623 extensions::SetLaunchType(profile_, controller->app_id(), launch_type); | 562 extensions::SetLaunchType(profile_, controller->app_id(), launch_type); |
| 624 } | 563 } |
| 625 | 564 |
| 626 void ChromeLauncherControllerImpl::PersistPinnedState() { | |
| 627 if (ignore_persist_pinned_state_change_) | |
| 628 return; | |
| 629 // It is a coding error to call PersistPinnedState() if the pinned apps are | |
| 630 // not user-editable. The code should check earlier and not perform any | |
| 631 // modification actions that trigger persisting the state. | |
| 632 // Mutating kPinnedLauncherApps is going to notify us and trigger us to | |
| 633 // process the change. We don't want that to happen so remove ourselves as a | |
| 634 // listener. | |
| 635 pref_change_registrar_.Remove(prefs::kPinnedLauncherApps); | |
| 636 { | |
| 637 std::unique_ptr<const base::ListValue> pinned_apps_pref = | |
| 638 profile_->GetPrefs() | |
| 639 ->GetList(prefs::kPinnedLauncherApps) | |
| 640 ->CreateDeepCopy(); | |
| 641 | |
| 642 const base::ListValue* policy_pinned_apps_pref = | |
| 643 profile_->GetPrefs()->GetList(prefs::kPolicyPinnedLauncherApps); | |
| 644 | |
| 645 ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps); | |
| 646 updater->Clear(); | |
| 647 for (size_t i = 0; i < model_->items().size(); ++i) { | |
| 648 if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) { | |
| 649 ash::ShelfID id = model_->items()[i].id; | |
| 650 LauncherItemController* controller = GetLauncherItemController(id); | |
| 651 // Don't persist pinning state for apps that are handled internally and | |
| 652 // have pinnable state AppListControllerDelegate::NO_PIN. | |
| 653 if (controller && IsPinned(id) && | |
| 654 GetPinnable(controller->app_id()) != | |
| 655 AppListControllerDelegate::NO_PIN) { | |
| 656 base::DictionaryValue* app_value = | |
| 657 ash::CreateAppDict(controller->app_id()); | |
| 658 if (app_value) { | |
| 659 if (!IsAppForUserPinned(controller->app_id(), | |
| 660 pinned_apps_pref.get(), | |
| 661 policy_pinned_apps_pref)) | |
| 662 app_value->SetBoolean(ash::kPinnedAppsPrefPinnedByPolicy, true); | |
| 663 updater->Append(app_value); | |
| 664 } | |
| 665 } | |
| 666 } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) { | |
| 667 PersistChromeItemIndex(i); | |
| 668 } else if (model_->items()[i].type == ash::TYPE_APP_LIST) { | |
| 669 base::DictionaryValue* app_value = | |
| 670 ash::CreateAppDict(ash::kPinnedAppsPlaceholder); | |
| 671 if (app_value) | |
| 672 updater->Append(app_value); | |
| 673 } | |
| 674 } | |
| 675 } | |
| 676 pref_change_registrar_.Add( | |
| 677 prefs::kPinnedLauncherApps, | |
| 678 base::Bind(&ChromeLauncherControllerImpl::UpdateAppLaunchersFromPref, | |
| 679 base::Unretained(this))); | |
| 680 } | |
| 681 | |
| 682 Profile* ChromeLauncherControllerImpl::GetProfile() { | 565 Profile* ChromeLauncherControllerImpl::GetProfile() { |
| 683 return profile_; | 566 return profile_; |
| 684 } | 567 } |
| 685 | 568 |
| 686 void ChromeLauncherControllerImpl::UpdateAppState( | 569 void ChromeLauncherControllerImpl::UpdateAppState( |
| 687 content::WebContents* contents, | 570 content::WebContents* contents, |
| 688 AppState app_state) { | 571 AppState app_state) { |
| 689 std::string app_id = launcher_controller_helper_->GetAppID(contents); | 572 std::string app_id = launcher_controller_helper_->GetAppID(contents); |
| 690 | 573 |
| 691 // Check if the gMail app is loaded and it matches the given content. | 574 // Check if the gMail app is loaded and it matches the given content. |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 985 AccountId::FromUserEmail(user_id)); | 868 AccountId::FromUserEmail(user_id)); |
| 986 if (other_profile == profile_) | 869 if (other_profile == profile_) |
| 987 return false; | 870 return false; |
| 988 | 871 |
| 989 // Note: The Auto hide state from preferences is not the same as the actual | 872 // Note: The Auto hide state from preferences is not the same as the actual |
| 990 // visibility of the shelf. Depending on all the various states (full screen, | 873 // visibility of the shelf. Depending on all the various states (full screen, |
| 991 // no window on desktop, multi user, ..) the shelf could be shown - or not. | 874 // no window on desktop, multi user, ..) the shelf could be shown - or not. |
| 992 PrefService* prefs = profile_->GetPrefs(); | 875 PrefService* prefs = profile_->GetPrefs(); |
| 993 PrefService* other_prefs = other_profile->GetPrefs(); | 876 PrefService* other_prefs = other_profile->GetPrefs(); |
| 994 const int64_t display = GetDisplayIDForShelf(shelf); | 877 const int64_t display = GetDisplayIDForShelf(shelf); |
| 995 bool currently_shown = ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER == | 878 const bool currently_shown = |
| 996 ash::GetShelfAutoHideBehaviorPref(prefs, display); | 879 ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER == |
| 997 bool other_shown = ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER == | 880 ash::launcher::GetShelfAutoHideBehaviorPref(prefs, display); |
| 998 ash::GetShelfAutoHideBehaviorPref(other_prefs, display); | 881 const bool other_shown = |
| 882 ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER == |
| 883 ash::launcher::GetShelfAutoHideBehaviorPref(other_prefs, display); |
| 999 | 884 |
| 1000 return currently_shown != other_shown || | 885 return currently_shown != other_shown || |
| 1001 ash::GetShelfAlignmentPref(prefs, display) != | 886 ash::launcher::GetShelfAlignmentPref(prefs, display) != |
| 1002 ash::GetShelfAlignmentPref(other_prefs, display); | 887 ash::launcher::GetShelfAlignmentPref(other_prefs, display); |
| 1003 } | 888 } |
| 1004 | 889 |
| 1005 void ChromeLauncherControllerImpl::OnUserProfileReadyToSwitch( | 890 void ChromeLauncherControllerImpl::OnUserProfileReadyToSwitch( |
| 1006 Profile* profile) { | 891 Profile* profile) { |
| 1007 if (user_switch_observer_.get()) | 892 if (user_switch_observer_.get()) |
| 1008 user_switch_observer_->OnUserProfileReadyToSwitch(profile); | 893 user_switch_observer_->OnUserProfileReadyToSwitch(profile); |
| 1009 } | 894 } |
| 1010 | 895 |
| 1011 AppListControllerDelegate::Pinnable ChromeLauncherControllerImpl::GetPinnable( | 896 AppListControllerDelegate::Pinnable ChromeLauncherControllerImpl::GetPinnable( |
| 1012 const std::string& app_id) { | 897 const std::string& app_id) { |
| 1013 for (size_t i = 0; i < kPinProhibitedExtensionIdsLength; ++i) { | |
| 1014 if (kPinProhibitedExtensionIds[i] == app_id) | |
| 1015 return AppListControllerDelegate::NO_PIN; | |
| 1016 } | |
| 1017 | |
| 1018 const base::ListValue* pref = | 898 const base::ListValue* pref = |
| 1019 profile_->GetPrefs()->GetList(prefs::kPolicyPinnedLauncherApps); | 899 profile_->GetPrefs()->GetList(prefs::kPolicyPinnedLauncherApps); |
| 1020 if (!pref) | 900 if (!pref) |
| 1021 return AppListControllerDelegate::PIN_EDITABLE; | 901 return AppListControllerDelegate::PIN_EDITABLE; |
| 1022 | 902 |
| 1023 // Pinned ARC apps policy defines the package name of the apps, that must | 903 // Pinned ARC apps policy defines the package name of the apps, that must |
| 1024 // be pinned. All the launch activities of any package in policy are pinned. | 904 // be pinned. All the launch activities of any package in policy are pinned. |
| 1025 // In turn the input parameter to this function is app_id, which | 905 // In turn the input parameter to this function is app_id, which |
| 1026 // is 32 chars hash. In case of ARC app this is a hash of | 906 // is 32 chars hash. In case of ARC app this is a hash of |
| 1027 // (package name + activity). This means that we must identify the package | 907 // (package name + activity). This means that we must identify the package |
| 1028 // from the hash, and check if this package is pinned by policy. | 908 // from the hash, and check if this package is pinned by policy. |
| 1029 const ArcAppListPrefs* const arc_prefs = ArcAppListPrefs::Get(GetProfile()); | 909 const ArcAppListPrefs* const arc_prefs = ArcAppListPrefs::Get(GetProfile()); |
| 1030 std::string arc_app_packege_name; | 910 std::string arc_app_packege_name; |
| 1031 if (arc_prefs) { | 911 if (arc_prefs) { |
| 1032 std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = | 912 std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = |
| 1033 arc_prefs->GetApp(app_id); | 913 arc_prefs->GetApp(app_id); |
| 1034 if (app_info) | 914 if (app_info) |
| 1035 arc_app_packege_name = app_info->package_name; | 915 arc_app_packege_name = app_info->package_name; |
| 1036 } | 916 } |
| 1037 | 917 |
| 1038 for (size_t index = 0; index < pref->GetSize(); ++index) { | 918 for (size_t index = 0; index < pref->GetSize(); ++index) { |
| 1039 const base::DictionaryValue* app = nullptr; | 919 const base::DictionaryValue* app = nullptr; |
| 1040 std::string app_id_or_package; | 920 std::string app_id_or_package; |
| 1041 if (pref->GetDictionary(index, &app) && | 921 if (pref->GetDictionary(index, &app) && |
| 1042 app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id_or_package) && | 922 app->GetString(ash::launcher::kPinnedAppsPrefAppIDPath, |
| 923 &app_id_or_package) && |
| 1043 (app_id == app_id_or_package || | 924 (app_id == app_id_or_package || |
| 1044 arc_app_packege_name == app_id_or_package)) { | 925 arc_app_packege_name == app_id_or_package)) { |
| 1045 return AppListControllerDelegate::PIN_FIXED; | 926 return AppListControllerDelegate::PIN_FIXED; |
| 1046 } | 927 } |
| 1047 } | 928 } |
| 1048 return AppListControllerDelegate::PIN_EDITABLE; | 929 return AppListControllerDelegate::PIN_EDITABLE; |
| 1049 } | 930 } |
| 1050 | 931 |
| 1051 ArcAppDeferredLauncherController* | 932 ArcAppDeferredLauncherController* |
| 1052 ChromeLauncherControllerImpl::GetArcDeferredLauncher() { | 933 ChromeLauncherControllerImpl::GetArcDeferredLauncher() { |
| 1053 return arc_deferred_launcher_.get(); | 934 return arc_deferred_launcher_.get(); |
| 1054 } | 935 } |
| 1055 | 936 |
| 1056 /////////////////////////////////////////////////////////////////////////////// | 937 /////////////////////////////////////////////////////////////////////////////// |
| 1057 // ash::ShelfDelegate: | 938 // ash::ShelfDelegate: |
| 1058 | 939 |
| 1059 void ChromeLauncherControllerImpl::OnShelfCreated(ash::Shelf* shelf) { | 940 void ChromeLauncherControllerImpl::OnShelfCreated(ash::Shelf* shelf) { |
| 1060 PrefService* prefs = profile_->GetPrefs(); | 941 PrefService* prefs = profile_->GetPrefs(); |
| 1061 const int64_t display = GetDisplayIDForShelf(shelf); | 942 const int64_t display = GetDisplayIDForShelf(shelf); |
| 1062 | 943 |
| 1063 shelf->SetAutoHideBehavior(ash::GetShelfAutoHideBehaviorPref(prefs, display)); | 944 shelf->SetAutoHideBehavior( |
| 945 ash::launcher::GetShelfAutoHideBehaviorPref(prefs, display)); |
| 1064 | 946 |
| 1065 if (ash::ShelfWidget::ShelfAlignmentAllowed()) | 947 if (ash::ShelfWidget::ShelfAlignmentAllowed()) |
| 1066 shelf->SetAlignment(ash::GetShelfAlignmentPref(prefs, display)); | 948 shelf->SetAlignment(ash::launcher::GetShelfAlignmentPref(prefs, display)); |
| 1067 } | 949 } |
| 1068 | 950 |
| 1069 void ChromeLauncherControllerImpl::OnShelfDestroyed(ash::Shelf* shelf) {} | 951 void ChromeLauncherControllerImpl::OnShelfDestroyed(ash::Shelf* shelf) {} |
| 1070 | 952 |
| 1071 void ChromeLauncherControllerImpl::OnShelfAlignmentChanged(ash::Shelf* shelf) { | 953 void ChromeLauncherControllerImpl::OnShelfAlignmentChanged(ash::Shelf* shelf) { |
| 1072 ash::SetShelfAlignmentPref(profile_->GetPrefs(), GetDisplayIDForShelf(shelf), | 954 ash::launcher::SetShelfAlignmentPref( |
| 1073 shelf->alignment()); | 955 profile_->GetPrefs(), GetDisplayIDForShelf(shelf), shelf->alignment()); |
| 1074 } | 956 } |
| 1075 | 957 |
| 1076 void ChromeLauncherControllerImpl::OnShelfAutoHideBehaviorChanged( | 958 void ChromeLauncherControllerImpl::OnShelfAutoHideBehaviorChanged( |
| 1077 ash::Shelf* shelf) { | 959 ash::Shelf* shelf) { |
| 1078 ash::SetShelfAutoHideBehaviorPref(profile_->GetPrefs(), | 960 ash::launcher::SetShelfAutoHideBehaviorPref(profile_->GetPrefs(), |
| 1079 GetDisplayIDForShelf(shelf), | 961 GetDisplayIDForShelf(shelf), |
| 1080 shelf->auto_hide_behavior()); | 962 shelf->auto_hide_behavior()); |
| 1081 } | 963 } |
| 1082 | 964 |
| 1083 void ChromeLauncherControllerImpl::OnShelfAutoHideStateChanged( | 965 void ChromeLauncherControllerImpl::OnShelfAutoHideStateChanged( |
| 1084 ash::Shelf* shelf) {} | 966 ash::Shelf* shelf) {} |
| 1085 | 967 |
| 1086 void ChromeLauncherControllerImpl::OnShelfVisibilityStateChanged( | 968 void ChromeLauncherControllerImpl::OnShelfVisibilityStateChanged( |
| 1087 ash::Shelf* shelf) {} | 969 ash::Shelf* shelf) {} |
| 1088 | 970 |
| 1089 ash::ShelfID ChromeLauncherControllerImpl::GetShelfIDForAppID( | 971 ash::ShelfID ChromeLauncherControllerImpl::GetShelfIDForAppID( |
| 1090 const std::string& app_id) { | 972 const std::string& app_id) { |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1295 if (IsAppPinned(app_id)) | 1177 if (IsAppPinned(app_id)) |
| 1296 return; | 1178 return; |
| 1297 | 1179 |
| 1298 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id); | 1180 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id); |
| 1299 if (shelf_id) { | 1181 if (shelf_id) { |
| 1300 // App item exists, pin it | 1182 // App item exists, pin it |
| 1301 Pin(shelf_id); | 1183 Pin(shelf_id); |
| 1302 } else { | 1184 } else { |
| 1303 // Otherwise, create a shortcut item for it. | 1185 // Otherwise, create a shortcut item for it. |
| 1304 shelf_id = CreateAppShortcutLauncherItem(app_id, model_->item_count()); | 1186 shelf_id = CreateAppShortcutLauncherItem(app_id, model_->item_count()); |
| 1305 if (GetPinnable(app_id) == AppListControllerDelegate::PIN_EDITABLE) | 1187 SyncPinPosition(shelf_id); |
| 1306 PersistPinnedState(); | |
| 1307 } | 1188 } |
| 1308 } | 1189 } |
| 1309 | 1190 |
| 1310 void ChromeLauncherControllerImpl::DoUnpinAppWithID(const std::string& app_id) { | 1191 void ChromeLauncherControllerImpl::DoUnpinAppWithID(const std::string& app_id) { |
| 1311 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id); | 1192 ash::ShelfID shelf_id = GetShelfIDForAppID(app_id); |
| 1312 if (shelf_id && IsPinned(shelf_id)) | 1193 if (shelf_id && IsPinned(shelf_id)) |
| 1313 Unpin(shelf_id); | 1194 Unpin(shelf_id); |
| 1314 } | 1195 } |
| 1315 | 1196 |
| 1316 int ChromeLauncherControllerImpl::PinRunningAppInternal(int index, | 1197 int ChromeLauncherControllerImpl::PinRunningAppInternal(int index, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1337 DCHECK_EQ(item.type, ash::TYPE_APP_SHORTCUT); | 1218 DCHECK_EQ(item.type, ash::TYPE_APP_SHORTCUT); |
| 1338 item.type = ash::TYPE_WINDOWED_APP; | 1219 item.type = ash::TYPE_WINDOWED_APP; |
| 1339 // A platform app and a windowed app are sharing TYPE_APP_SHORTCUT. As such | 1220 // A platform app and a windowed app are sharing TYPE_APP_SHORTCUT. As such |
| 1340 // we have to check here what this was before it got a shortcut. | 1221 // we have to check here what this was before it got a shortcut. |
| 1341 LauncherItemController* controller = GetLauncherItemController(item.id); | 1222 LauncherItemController* controller = GetLauncherItemController(item.id); |
| 1342 if (controller && controller->type() == LauncherItemController::TYPE_APP) | 1223 if (controller && controller->type() == LauncherItemController::TYPE_APP) |
| 1343 item.type = ash::TYPE_PLATFORM_APP; | 1224 item.type = ash::TYPE_PLATFORM_APP; |
| 1344 model_->Set(index, item); | 1225 model_->Set(index, item); |
| 1345 } | 1226 } |
| 1346 | 1227 |
| 1228 void ChromeLauncherControllerImpl::SyncPinPosition(ash::ShelfID shelf_id) { |
| 1229 DCHECK(shelf_id); |
| 1230 if (ignore_persist_pinned_state_change_) |
| 1231 return; |
| 1232 |
| 1233 const int max_index = model_->item_count(); |
| 1234 const int index = model_->ItemIndexByID(shelf_id); |
| 1235 DCHECK_GT(index, 0); |
| 1236 |
| 1237 const std::string& app_id = GetAppIDForShelfID(shelf_id); |
| 1238 DCHECK(!app_id.empty()); |
| 1239 |
| 1240 std::string app_id_before; |
| 1241 std::string app_id_after; |
| 1242 |
| 1243 for (int i = index - 1; i > 0; --i) { |
| 1244 const ash::ShelfID shelf_id_before = model_->items()[i].id; |
| 1245 if (IsPinned(shelf_id_before)) { |
| 1246 app_id_before = GetAppIDForShelfID(shelf_id_before); |
| 1247 DCHECK(!app_id_before.empty()); |
| 1248 break; |
| 1249 } |
| 1250 } |
| 1251 |
| 1252 for (int i = index + 1; i < max_index; ++i) { |
| 1253 const ash::ShelfID shelf_id_after = model_->items()[i].id; |
| 1254 if (IsPinned(shelf_id_after)) { |
| 1255 app_id_after = GetAppIDForShelfID(shelf_id_after); |
| 1256 DCHECK(!app_id_after.empty()); |
| 1257 break; |
| 1258 } |
| 1259 } |
| 1260 |
| 1261 ash::launcher::SetPinPosition(profile_, app_id, app_id_before, app_id_after); |
| 1262 } |
| 1263 |
| 1264 void ChromeLauncherControllerImpl::OnSyncModelUpdated() { |
| 1265 UpdateAppLaunchersFromPref(); |
| 1266 } |
| 1267 |
| 1347 void ChromeLauncherControllerImpl::UpdateAppLaunchersFromPref() { | 1268 void ChromeLauncherControllerImpl::UpdateAppLaunchersFromPref() { |
| 1348 // There are various functions which will trigger a |PersistPinnedState| call | 1269 // There are various functions which will trigger a |SyncPinPosition| call |
| 1349 // like a direct call to |DoPinAppWithID|, or an indirect call to the menu | 1270 // like a direct call to |DoPinAppWithID|, or an indirect call to the menu |
| 1350 // model which will use weights to re-arrange the icons to new positions. | 1271 // model which will use weights to re-arrange the icons to new positions. |
| 1351 // Since this function is meant to synchronize the "is state" with the | 1272 // Since this function is meant to synchronize the "is state" with the |
| 1352 // "sync state", it makes no sense to store any changes by this function back | 1273 // "sync state", it makes no sense to store any changes by this function back |
| 1353 // into the pref state. Therefore we tell |persistPinnedState| to ignore any | 1274 // into the pref state. Therefore we tell |persistPinnedState| to ignore any |
| 1354 // invocations while we are running. | 1275 // invocations while we are running. |
| 1355 base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true); | 1276 base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true); |
| 1356 std::vector<std::string> pinned_apps = ash::GetPinnedAppsFromPrefs( | 1277 std::vector<std::string> pinned_apps = ash::launcher::GetPinnedAppsFromPrefs( |
| 1357 profile_->GetPrefs(), launcher_controller_helper_.get()); | 1278 profile_->GetPrefs(), launcher_controller_helper_.get()); |
| 1358 | 1279 |
| 1359 int index = 0; | 1280 int index = 0; |
| 1360 int max_index = model_->item_count(); | 1281 int max_index = model_->item_count(); |
| 1282 int seen_chrome_index = -1; |
| 1361 | 1283 |
| 1362 // When one of the two special items cannot be moved (and we do not know where | 1284 // At least chrome browser shortcut should exist. |
| 1363 // yet), we remember the current location in one of these variables. | 1285 DCHECK_GT(max_index, 0); |
| 1364 int chrome_index = -1; | 1286 |
| 1365 int app_list_index = -1; | 1287 // Skip app list items if it exists. |
| 1288 if (model_->items()[0].type == ash::TYPE_APP_LIST) |
| 1289 ++index; |
| 1366 | 1290 |
| 1367 // Walk the model and |pinned_apps| from the pref lockstep, adding and | 1291 // Walk the model and |pinned_apps| from the pref lockstep, adding and |
| 1368 // removing items as necessary. NB: This code uses plain old indexing instead | 1292 // removing items as necessary. NB: This code uses plain old indexing instead |
| 1369 // of iterators because of model mutations as part of the loop. | 1293 // of iterators because of model mutations as part of the loop. |
| 1370 std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin()); | 1294 std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin()); |
| 1371 for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) { | 1295 for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) { |
| 1372 // Update apps icon if applicable. | 1296 // Update apps icon if applicable. |
| 1373 OnAppUpdated(profile_, *pref_app_id); | 1297 OnAppUpdated(profile_, *pref_app_id); |
| 1374 // Check if we have an item which we need to handle. | 1298 // Check if we have an item which we need to handle. |
| 1375 if (*pref_app_id == extension_misc::kChromeAppId || | 1299 if (IsAppPinned(*pref_app_id)) { |
| 1376 *pref_app_id == ash::kPinnedAppsPlaceholder || | 1300 if (seen_chrome_index >= 0 && |
| 1377 IsAppPinned(*pref_app_id)) { | 1301 *pref_app_id == extension_misc::kChromeAppId) { |
| 1302 // Current item is Chrome browser and we saw it before. |
| 1303 model_->Move(seen_chrome_index, index); |
| 1304 ++pref_app_id; |
| 1305 --index; |
| 1306 continue; |
| 1307 } |
| 1378 for (; index < max_index; ++index) { | 1308 for (; index < max_index; ++index) { |
| 1379 const ash::ShelfItem& item(model_->items()[index]); | 1309 const ash::ShelfItem& item(model_->items()[index]); |
| 1380 bool is_app_list = item.type == ash::TYPE_APP_LIST; | 1310 if (item.type != ash::TYPE_APP_SHORTCUT && |
| 1381 bool is_chrome = item.type == ash::TYPE_BROWSER_SHORTCUT; | 1311 item.type != ash::TYPE_BROWSER_SHORTCUT) { |
| 1382 if (item.type != ash::TYPE_APP_SHORTCUT && !is_app_list && !is_chrome) | |
| 1383 continue; | 1312 continue; |
| 1313 } |
| 1384 LauncherItemController* controller = GetLauncherItemController(item.id); | 1314 LauncherItemController* controller = GetLauncherItemController(item.id); |
| 1385 if ((ash::kPinnedAppsPlaceholder == *pref_app_id && is_app_list) || | 1315 if (controller && controller->app_id() == *pref_app_id) { |
| 1386 (extension_misc::kChromeAppId == *pref_app_id && is_chrome) || | |
| 1387 (controller && controller->app_id() == *pref_app_id)) { | |
| 1388 // Check if an item needs to be moved here. | |
| 1389 MoveChromeOrApplistToFinalPosition(is_chrome, is_app_list, index, | |
| 1390 &chrome_index, &app_list_index); | |
| 1391 ++pref_app_id; | 1316 ++pref_app_id; |
| 1392 break; | 1317 break; |
| 1318 } else if (item.type == ash::TYPE_BROWSER_SHORTCUT) { |
| 1319 // We cannot close browser shortcut. Remember its position. |
| 1320 seen_chrome_index = index; |
| 1393 } else { | 1321 } else { |
| 1394 if (is_chrome || is_app_list) { | 1322 // Check if this is a platform or a windowed app. |
| 1395 // We cannot delete any of these shortcuts. As such we remember | 1323 if (item.type == ash::TYPE_APP_SHORTCUT && controller && |
| 1396 // their positions and move them later where they belong. | 1324 (controller->locked() || |
| 1397 if (is_chrome) | 1325 controller->type() == LauncherItemController::TYPE_APP)) { |
| 1398 chrome_index = index; | 1326 // Note: This will not change the amount of items (|max_index|). |
| 1399 else | 1327 // Even changes to the actual |index| due to item weighting |
| 1400 app_list_index = index; | 1328 // changes should be fine. |
| 1401 // And skip the item - or exit the loop if end is reached (note that | 1329 UnpinRunningAppInternal(index); |
| 1402 // in that case we will reduce the index again by one and this only | |
| 1403 // compensates for it). | |
| 1404 if (index >= max_index - 1) | |
| 1405 break; | |
| 1406 ++index; | |
| 1407 } else { | 1330 } else { |
| 1408 // Check if this is a platform or a windowed app. | 1331 if (controller) |
| 1409 if (item.type == ash::TYPE_APP_SHORTCUT && controller && | 1332 LauncherItemClosed(item.id); |
| 1410 (controller->locked() || | 1333 --max_index; |
| 1411 controller->type() == LauncherItemController::TYPE_APP)) { | |
| 1412 // Note: This will not change the amount of items (|max_index|). | |
| 1413 // Even changes to the actual |index| due to item weighting | |
| 1414 // changes should be fine. | |
| 1415 UnpinRunningAppInternal(index); | |
| 1416 } else { | |
| 1417 if (controller) | |
| 1418 LauncherItemClosed(item.id); | |
| 1419 --max_index; | |
| 1420 } | |
| 1421 } | 1334 } |
| 1422 --index; | 1335 --index; |
| 1423 } | 1336 } |
| 1424 } | 1337 } |
| 1425 // If the item wasn't found, that means id_to_item_controller_map_ | 1338 // If the item wasn't found, that means id_to_item_controller_map_ |
| 1426 // is out of sync. | 1339 // is out of sync. |
| 1427 DCHECK(index <= max_index); | 1340 DCHECK(index <= max_index); |
| 1428 } else { | 1341 } else { |
| 1429 // Check if the item was already running but not yet pinned. | 1342 // Check if the item was already running but not yet pinned. |
| 1430 ash::ShelfID shelf_id = GetShelfIDForAppID(*pref_app_id); | 1343 ash::ShelfID shelf_id = GetShelfIDForAppID(*pref_app_id); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1448 LauncherItemController* controller = GetLauncherItemController(item.id); | 1361 LauncherItemController* controller = GetLauncherItemController(item.id); |
| 1449 if (controller) { | 1362 if (controller) { |
| 1450 if (controller->locked() || | 1363 if (controller->locked() || |
| 1451 controller->type() == LauncherItemController::TYPE_APP) { | 1364 controller->type() == LauncherItemController::TYPE_APP) { |
| 1452 UnpinRunningAppInternal(index); | 1365 UnpinRunningAppInternal(index); |
| 1453 } else { | 1366 } else { |
| 1454 LauncherItemClosed(item.id); | 1367 LauncherItemClosed(item.id); |
| 1455 } | 1368 } |
| 1456 } | 1369 } |
| 1457 } else { | 1370 } else { |
| 1458 if (item.type == ash::TYPE_BROWSER_SHORTCUT) | |
| 1459 chrome_index = index; | |
| 1460 else if (item.type == ash::TYPE_APP_LIST) | |
| 1461 app_list_index = index; | |
| 1462 ++index; | 1371 ++index; |
| 1463 } | 1372 } |
| 1464 } | 1373 } |
| 1465 | 1374 |
| 1466 // Append unprocessed items from the pref to the end of the model. | 1375 // Append unprocessed items from the pref to the end of the model. |
| 1467 for (; pref_app_id != pinned_apps.end(); ++pref_app_id) { | 1376 for (; pref_app_id != pinned_apps.end(); ++pref_app_id) { |
| 1468 // Update apps icon if applicable. | 1377 // Update apps icon if applicable. |
| 1469 OnAppUpdated(profile_, *pref_app_id); | 1378 OnAppUpdated(profile_, *pref_app_id); |
| 1470 // All items but the chrome and / or app list shortcut needs to be added. | 1379 if (*pref_app_id == extension_misc::kChromeAppId) { |
| 1471 bool is_chrome = *pref_app_id == extension_misc::kChromeAppId; | 1380 int target_index = FindInsertionPoint(); |
| 1472 bool is_app_list = *pref_app_id == ash::kPinnedAppsPlaceholder; | 1381 DCHECK(seen_chrome_index >= 0 && seen_chrome_index < target_index); |
| 1473 // Coming here we know the next item which can be finalized, either the | 1382 model_->Move(seen_chrome_index, target_index); |
| 1474 // chrome item or the app launcher. The final position is the end of the | 1383 } else { |
| 1475 // list. The menu model will make sure that the item is grouped according | |
| 1476 // to its weight (which we do not know here). | |
| 1477 if (!is_chrome && !is_app_list) { | |
| 1478 DoPinAppWithID(*pref_app_id); | 1384 DoPinAppWithID(*pref_app_id); |
| 1479 int target_index = FindInsertionPoint(false); | 1385 int target_index = FindInsertionPoint(); |
| 1480 ash::ShelfID id = GetShelfIDForAppID(*pref_app_id); | 1386 ash::ShelfID id = GetShelfIDForAppID(*pref_app_id); |
| 1481 int source_index = model_->ItemIndexByID(id); | 1387 int source_index = model_->ItemIndexByID(id); |
| 1482 if (source_index != target_index) | 1388 if (source_index != target_index) |
| 1483 model_->Move(source_index, target_index); | 1389 model_->Move(source_index, target_index); |
| 1484 | |
| 1485 // Needed for the old layout - the weight might force it to be lower in | |
| 1486 // rank. | |
| 1487 if (app_list_index != -1 && target_index <= app_list_index) | |
| 1488 ++app_list_index; | |
| 1489 } else { | |
| 1490 int target_index = FindInsertionPoint(is_app_list); | |
| 1491 MoveChromeOrApplistToFinalPosition(is_chrome, is_app_list, target_index, | |
| 1492 &chrome_index, &app_list_index); | |
| 1493 } | 1390 } |
| 1494 } | 1391 } |
| 1495 } | 1392 } |
| 1496 | 1393 |
| 1497 void ChromeLauncherControllerImpl::SetShelfAutoHideBehaviorFromPrefs() { | 1394 void ChromeLauncherControllerImpl::SetShelfAutoHideBehaviorFromPrefs() { |
| 1498 for (auto* window : ash::Shell::GetAllRootWindows()) { | 1395 for (auto* window : ash::Shell::GetAllRootWindows()) { |
| 1499 ash::Shelf* shelf = ash::Shelf::ForWindow(window); | 1396 ash::Shelf* shelf = ash::Shelf::ForWindow(window); |
| 1500 if (shelf) { | 1397 if (shelf) { |
| 1501 shelf->SetAutoHideBehavior(ash::GetShelfAutoHideBehaviorPref( | 1398 shelf->SetAutoHideBehavior(ash::launcher::GetShelfAutoHideBehaviorPref( |
| 1502 profile_->GetPrefs(), GetDisplayIDForShelf(shelf))); | 1399 profile_->GetPrefs(), GetDisplayIDForShelf(shelf))); |
| 1503 } | 1400 } |
| 1504 } | 1401 } |
| 1505 } | 1402 } |
| 1506 | 1403 |
| 1507 void ChromeLauncherControllerImpl::SetShelfAlignmentFromPrefs() { | 1404 void ChromeLauncherControllerImpl::SetShelfAlignmentFromPrefs() { |
| 1508 if (!ash::ShelfWidget::ShelfAlignmentAllowed()) | 1405 if (!ash::ShelfWidget::ShelfAlignmentAllowed()) |
| 1509 return; | 1406 return; |
| 1510 | 1407 |
| 1511 for (auto* window : ash::Shell::GetAllRootWindows()) { | 1408 for (auto* window : ash::Shell::GetAllRootWindows()) { |
| 1512 ash::Shelf* shelf = ash::Shelf::ForWindow(window); | 1409 ash::Shelf* shelf = ash::Shelf::ForWindow(window); |
| 1513 if (shelf) { | 1410 if (shelf) { |
| 1514 shelf->SetAlignment(ash::GetShelfAlignmentPref( | 1411 shelf->SetAlignment(ash::launcher::GetShelfAlignmentPref( |
| 1515 profile_->GetPrefs(), GetDisplayIDForShelf(shelf))); | 1412 profile_->GetPrefs(), GetDisplayIDForShelf(shelf))); |
| 1516 } | 1413 } |
| 1517 } | 1414 } |
| 1518 } | 1415 } |
| 1519 | 1416 |
| 1520 void ChromeLauncherControllerImpl::SetShelfBehaviorsFromPrefs() { | 1417 void ChromeLauncherControllerImpl::SetShelfBehaviorsFromPrefs() { |
| 1521 SetShelfAutoHideBehaviorFromPrefs(); | 1418 SetShelfAutoHideBehaviorFromPrefs(); |
| 1522 SetShelfAlignmentFromPrefs(); | 1419 SetShelfAlignmentFromPrefs(); |
| 1523 } | 1420 } |
| 1524 | 1421 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1608 static_cast<AppShortcutLauncherItemController*>(controller); | 1505 static_cast<AppShortcutLauncherItemController*>(controller); |
| 1609 return app_controller->GetRunningApplications(); | 1506 return app_controller->GetRunningApplications(); |
| 1610 } | 1507 } |
| 1611 | 1508 |
| 1612 ash::ShelfID ChromeLauncherControllerImpl::CreateBrowserShortcutLauncherItem() { | 1509 ash::ShelfID ChromeLauncherControllerImpl::CreateBrowserShortcutLauncherItem() { |
| 1613 ash::ShelfItem browser_shortcut; | 1510 ash::ShelfItem browser_shortcut; |
| 1614 browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT; | 1511 browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT; |
| 1615 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 1512 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 1616 browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32); | 1513 browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32); |
| 1617 ash::ShelfID id = model_->next_id(); | 1514 ash::ShelfID id = model_->next_id(); |
| 1618 size_t index = GetChromeIconIndexForCreation(); | 1515 model_->AddAt(0, browser_shortcut); |
| 1619 model_->AddAt(index, browser_shortcut); | |
| 1620 id_to_item_controller_map_[id] = | 1516 id_to_item_controller_map_[id] = |
| 1621 new BrowserShortcutLauncherItemController(this, model_); | 1517 new BrowserShortcutLauncherItemController(this, model_); |
| 1622 id_to_item_controller_map_[id]->set_shelf_id(id); | 1518 id_to_item_controller_map_[id]->set_shelf_id(id); |
| 1623 // ShelfItemDelegateManager owns BrowserShortcutLauncherItemController. | 1519 // ShelfItemDelegateManager owns BrowserShortcutLauncherItemController. |
| 1624 SetShelfItemDelegate(id, id_to_item_controller_map_[id]); | 1520 SetShelfItemDelegate(id, id_to_item_controller_map_[id]); |
| 1625 return id; | 1521 return id; |
| 1626 } | 1522 } |
| 1627 | 1523 |
| 1628 bool ChromeLauncherControllerImpl::IsIncognito( | 1524 bool ChromeLauncherControllerImpl::IsIncognito( |
| 1629 const content::WebContents* web_contents) const { | 1525 const content::WebContents* web_contents) const { |
| 1630 const Profile* profile = | 1526 const Profile* profile = |
| 1631 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 1527 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 1632 return profile->IsOffTheRecord() && !profile->IsGuestSession() && | 1528 return profile->IsOffTheRecord() && !profile->IsGuestSession() && |
| 1633 !profile->IsSystemProfile(); | 1529 !profile->IsSystemProfile(); |
| 1634 } | 1530 } |
| 1635 | 1531 |
| 1636 void ChromeLauncherControllerImpl::PersistChromeItemIndex(int index) { | 1532 int ChromeLauncherControllerImpl::FindInsertionPoint() { |
| 1637 profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index); | 1533 DCHECK_GT(model_->item_count(), 0); |
| 1638 } | |
| 1639 | |
| 1640 void ChromeLauncherControllerImpl::MoveChromeOrApplistToFinalPosition( | |
| 1641 bool is_chrome, | |
| 1642 bool is_app_list, | |
| 1643 int target_index, | |
| 1644 int* chrome_index, | |
| 1645 int* app_list_index) { | |
| 1646 if (is_chrome && *chrome_index != -1) { | |
| 1647 model_->Move(*chrome_index, target_index); | |
| 1648 if (*app_list_index != -1 && *chrome_index < *app_list_index && | |
| 1649 target_index > *app_list_index) | |
| 1650 --(*app_list_index); | |
| 1651 *chrome_index = -1; | |
| 1652 } else if (is_app_list && *app_list_index != -1) { | |
| 1653 model_->Move(*app_list_index, target_index); | |
| 1654 if (*chrome_index != -1 && *app_list_index < *chrome_index && | |
| 1655 target_index > *chrome_index) | |
| 1656 --(*chrome_index); | |
| 1657 *app_list_index = -1; | |
| 1658 } | |
| 1659 } | |
| 1660 | |
| 1661 int ChromeLauncherControllerImpl::FindInsertionPoint(bool is_app_list) { | |
| 1662 // Keeping this change small to backport to M33&32 (see crbug.com/329597). | |
| 1663 // TODO(skuhne): With the removal of the legacy shelf layout we should remove | |
| 1664 // the ability to move the app list item since this was never used. We should | |
| 1665 // instead ask the ShelfModel::ValidateInsertionIndex or similir for an index. | |
| 1666 if (is_app_list) | |
| 1667 return 0; | |
| 1668 | |
| 1669 for (int i = model_->item_count() - 1; i > 0; --i) { | 1534 for (int i = model_->item_count() - 1; i > 0; --i) { |
| 1670 ash::ShelfItemType type = model_->items()[i].type; | 1535 ash::ShelfItemType type = model_->items()[i].type; |
| 1536 DCHECK_NE(ash::TYPE_APP_LIST, type); |
| 1671 if (type == ash::TYPE_APP_SHORTCUT || | 1537 if (type == ash::TYPE_APP_SHORTCUT || |
| 1672 (is_app_list && type == ash::TYPE_APP_LIST) || | |
| 1673 type == ash::TYPE_BROWSER_SHORTCUT) { | 1538 type == ash::TYPE_BROWSER_SHORTCUT) { |
| 1674 return i; | 1539 return i; |
| 1675 } | 1540 } |
| 1676 } | 1541 } |
| 1677 return 0; | 1542 return 0; |
| 1678 } | 1543 } |
| 1679 | 1544 |
| 1680 int ChromeLauncherControllerImpl::GetChromeIconIndexForCreation() { | |
| 1681 // We get the list of pinned apps as they currently would get pinned. | |
| 1682 // Within this list the chrome icon will be the correct location. | |
| 1683 std::vector<std::string> pinned_apps = ash::GetPinnedAppsFromPrefs( | |
| 1684 profile_->GetPrefs(), launcher_controller_helper_.get()); | |
| 1685 | |
| 1686 std::vector<std::string>::iterator it = | |
| 1687 std::find(pinned_apps.begin(), pinned_apps.end(), | |
| 1688 std::string(extension_misc::kChromeAppId)); | |
| 1689 DCHECK(it != pinned_apps.end()); | |
| 1690 int index = it - pinned_apps.begin(); | |
| 1691 | |
| 1692 // We should do here a comparison between the is state and the "want to be" | |
| 1693 // state since some apps might be able to pin but are not yet. Instead - for | |
| 1694 // the time being we clamp against the amount of known items and wait for the | |
| 1695 // next |UpdateAppLaunchersFromPref()| call to correct it - it will come since | |
| 1696 // the pinning will be done then. | |
| 1697 return std::min(model_->item_count(), index); | |
| 1698 } | |
| 1699 | |
| 1700 void ChromeLauncherControllerImpl::CloseWindowedAppsFromRemovedExtension( | 1545 void ChromeLauncherControllerImpl::CloseWindowedAppsFromRemovedExtension( |
| 1701 const std::string& app_id, | 1546 const std::string& app_id, |
| 1702 const Profile* profile) { | 1547 const Profile* profile) { |
| 1703 // This function cannot rely on the controller's enumeration functionality | 1548 // This function cannot rely on the controller's enumeration functionality |
| 1704 // since the extension has already be unloaded. | 1549 // since the extension has already be unloaded. |
| 1705 const BrowserList* browser_list = BrowserList::GetInstance(); | 1550 const BrowserList* browser_list = BrowserList::GetInstance(); |
| 1706 std::vector<Browser*> browser_to_close; | 1551 std::vector<Browser*> browser_to_close; |
| 1707 for (BrowserList::const_reverse_iterator it = | 1552 for (BrowserList::const_reverse_iterator it = |
| 1708 browser_list->begin_last_active(); | 1553 browser_list->begin_last_active(); |
| 1709 it != browser_list->end_last_active(); ++it) { | 1554 it != browser_list->end_last_active(); ++it) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1752 app_icon_loaders_.push_back(std::move(extension_app_icon_loader)); | 1597 app_icon_loaders_.push_back(std::move(extension_app_icon_loader)); |
| 1753 | 1598 |
| 1754 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) { | 1599 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) { |
| 1755 std::unique_ptr<AppIconLoader> arc_app_icon_loader(new ArcAppIconLoader( | 1600 std::unique_ptr<AppIconLoader> arc_app_icon_loader(new ArcAppIconLoader( |
| 1756 profile_, extension_misc::EXTENSION_ICON_SMALL, this)); | 1601 profile_, extension_misc::EXTENSION_ICON_SMALL, this)); |
| 1757 app_icon_loaders_.push_back(std::move(arc_app_icon_loader)); | 1602 app_icon_loaders_.push_back(std::move(arc_app_icon_loader)); |
| 1758 } | 1603 } |
| 1759 | 1604 |
| 1760 pref_change_registrar_.Init(profile_->GetPrefs()); | 1605 pref_change_registrar_.Init(profile_->GetPrefs()); |
| 1761 pref_change_registrar_.Add( | 1606 pref_change_registrar_.Add( |
| 1762 prefs::kPinnedLauncherApps, | |
| 1763 base::Bind(&ChromeLauncherControllerImpl::UpdateAppLaunchersFromPref, | |
| 1764 base::Unretained(this))); | |
| 1765 pref_change_registrar_.Add( | |
| 1766 prefs::kPolicyPinnedLauncherApps, | 1607 prefs::kPolicyPinnedLauncherApps, |
| 1767 base::Bind(&ChromeLauncherControllerImpl::UpdateAppLaunchersFromPref, | 1608 base::Bind(&ChromeLauncherControllerImpl::UpdateAppLaunchersFromPref, |
| 1768 base::Unretained(this))); | 1609 base::Unretained(this))); |
| 1769 pref_change_registrar_.Add( | 1610 pref_change_registrar_.Add( |
| 1770 prefs::kShelfAlignmentLocal, | 1611 prefs::kShelfAlignmentLocal, |
| 1771 base::Bind(&ChromeLauncherControllerImpl::SetShelfAlignmentFromPrefs, | 1612 base::Bind(&ChromeLauncherControllerImpl::SetShelfAlignmentFromPrefs, |
| 1772 base::Unretained(this))); | 1613 base::Unretained(this))); |
| 1773 pref_change_registrar_.Add( | 1614 pref_change_registrar_.Add( |
| 1774 prefs::kShelfAutoHideBehaviorLocal, | 1615 prefs::kShelfAutoHideBehaviorLocal, |
| 1775 base::Bind( | 1616 base::Bind( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1787 | 1628 |
| 1788 std::unique_ptr<LauncherAppUpdater> extension_app_updater( | 1629 std::unique_ptr<LauncherAppUpdater> extension_app_updater( |
| 1789 new LauncherExtensionAppUpdater(this, profile_)); | 1630 new LauncherExtensionAppUpdater(this, profile_)); |
| 1790 app_updaters_.push_back(std::move(extension_app_updater)); | 1631 app_updaters_.push_back(std::move(extension_app_updater)); |
| 1791 | 1632 |
| 1792 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) { | 1633 if (arc::ArcAuthService::IsAllowedForProfile(profile_)) { |
| 1793 std::unique_ptr<LauncherAppUpdater> arc_app_updater( | 1634 std::unique_ptr<LauncherAppUpdater> arc_app_updater( |
| 1794 new LauncherArcAppUpdater(this, profile_)); | 1635 new LauncherArcAppUpdater(this, profile_)); |
| 1795 app_updaters_.push_back(std::move(arc_app_updater)); | 1636 app_updaters_.push_back(std::move(arc_app_updater)); |
| 1796 } | 1637 } |
| 1638 |
| 1639 app_list::AppListSyncableService* app_service = |
| 1640 app_list::AppListSyncableServiceFactory::GetForProfile(profile_); |
| 1641 if (app_service) |
| 1642 app_service->AddObserverAndStart(this); |
| 1797 } | 1643 } |
| 1798 | 1644 |
| 1799 void ChromeLauncherControllerImpl::ReleaseProfile() { | 1645 void ChromeLauncherControllerImpl::ReleaseProfile() { |
| 1800 if (app_sync_ui_state_) | 1646 if (app_sync_ui_state_) |
| 1801 app_sync_ui_state_->RemoveObserver(this); | 1647 app_sync_ui_state_->RemoveObserver(this); |
| 1802 | 1648 |
| 1803 app_updaters_.clear(); | 1649 app_updaters_.clear(); |
| 1804 | 1650 |
| 1805 prefs_observer_.reset(); | 1651 prefs_observer_.reset(); |
| 1806 | 1652 |
| 1807 pref_change_registrar_.RemoveAll(); | 1653 pref_change_registrar_.RemoveAll(); |
| 1654 |
| 1655 app_list::AppListSyncableService* app_service = |
| 1656 app_list::AppListSyncableServiceFactory::GetForProfile(profile_); |
| 1657 if (app_service) |
| 1658 app_service->RemoveObserver(this); |
| 1808 } | 1659 } |
| 1809 | 1660 |
| 1810 AppIconLoader* ChromeLauncherControllerImpl::GetAppIconLoaderForApp( | 1661 AppIconLoader* ChromeLauncherControllerImpl::GetAppIconLoaderForApp( |
| 1811 const std::string& app_id) { | 1662 const std::string& app_id) { |
| 1812 for (const auto& app_icon_loader : app_icon_loaders_) { | 1663 for (const auto& app_icon_loader : app_icon_loaders_) { |
| 1813 if (app_icon_loader->CanLoadImageForApp(app_id)) | 1664 if (app_icon_loader->CanLoadImageForApp(app_id)) |
| 1814 return app_icon_loader.get(); | 1665 return app_icon_loader.get(); |
| 1815 } | 1666 } |
| 1816 | 1667 |
| 1817 return nullptr; | 1668 return nullptr; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1829 if (iter == id_to_item_controller_map_.end() || item_delegate == iter->second) | 1680 if (iter == id_to_item_controller_map_.end() || item_delegate == iter->second) |
| 1830 return; | 1681 return; |
| 1831 LOG(ERROR) << "Unexpected change of shelf item id: " << id; | 1682 LOG(ERROR) << "Unexpected change of shelf item id: " << id; |
| 1832 id_to_item_controller_map_.erase(iter); | 1683 id_to_item_controller_map_.erase(iter); |
| 1833 } | 1684 } |
| 1834 | 1685 |
| 1835 /////////////////////////////////////////////////////////////////////////////// | 1686 /////////////////////////////////////////////////////////////////////////////// |
| 1836 // ash::ShelfModelObserver: | 1687 // ash::ShelfModelObserver: |
| 1837 | 1688 |
| 1838 void ChromeLauncherControllerImpl::ShelfItemAdded(int index) { | 1689 void ChromeLauncherControllerImpl::ShelfItemAdded(int index) { |
| 1839 // The app list launcher can get added to the shelf after we applied the | |
| 1840 // preferences. In that case the item might be at the wrong spot. As such we | |
| 1841 // call the function again. | |
| 1842 if (model_->items()[index].type == ash::TYPE_APP_LIST) | |
| 1843 UpdateAppLaunchersFromPref(); | |
| 1844 } | 1690 } |
| 1845 | 1691 |
| 1846 void ChromeLauncherControllerImpl::ShelfItemRemoved(int index, | 1692 void ChromeLauncherControllerImpl::ShelfItemRemoved(int index, |
| 1847 ash::ShelfID id) { | 1693 ash::ShelfID id) { |
| 1848 // TODO(skuhne): This fixes crbug.com/429870, but it does not answer why we | 1694 // TODO(skuhne): This fixes crbug.com/429870, but it does not answer why we |
| 1849 // get into this state in the first place. | 1695 // get into this state in the first place. |
| 1850 IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id); | 1696 IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id); |
| 1851 if (iter == id_to_item_controller_map_.end()) | 1697 if (iter == id_to_item_controller_map_.end()) |
| 1852 return; | 1698 return; |
| 1853 | 1699 |
| 1854 LOG(ERROR) << "Unexpected change of shelf item id: " << id; | 1700 LOG(ERROR) << "Unexpected change of shelf item id: " << id; |
| 1855 | 1701 |
| 1856 id_to_item_controller_map_.erase(iter); | 1702 id_to_item_controller_map_.erase(iter); |
| 1857 } | 1703 } |
| 1858 | 1704 |
| 1859 void ChromeLauncherControllerImpl::ShelfItemMoved(int start_index, | 1705 void ChromeLauncherControllerImpl::ShelfItemMoved(int start_index, |
| 1860 int target_index) { | 1706 int target_index) { |
| 1861 const ash::ShelfItem& item = model_->items()[target_index]; | 1707 const ash::ShelfItem& item = model_->items()[target_index]; |
| 1862 // We remember the moved item position if it is either pinnable or | 1708 // We remember the moved item position if it is either pinnable or |
| 1863 // it is the app list with the alternate shelf layout. | 1709 // it is the app list with the alternate shelf layout. |
| 1864 if ((HasShelfIDToAppIDMapping(item.id) && IsPinned(item.id)) || | 1710 DCHECK_NE(ash::TYPE_APP_LIST, item.type); |
| 1865 item.type == ash::TYPE_APP_LIST) | 1711 if (HasShelfIDToAppIDMapping(item.id) && IsPinned(item.id)) |
| 1866 PersistPinnedState(); | 1712 SyncPinPosition(item.id); |
| 1867 } | 1713 } |
| 1868 | 1714 |
| 1869 void ChromeLauncherControllerImpl::ShelfItemChanged( | 1715 void ChromeLauncherControllerImpl::ShelfItemChanged( |
| 1870 int index, | 1716 int index, |
| 1871 const ash::ShelfItem& old_item) {} | 1717 const ash::ShelfItem& old_item) {} |
| 1872 | 1718 |
| 1873 /////////////////////////////////////////////////////////////////////////////// | 1719 /////////////////////////////////////////////////////////////////////////////// |
| 1874 // ash::WindowTreeHostManager::Observer: | 1720 // ash::WindowTreeHostManager::Observer: |
| 1875 | 1721 |
| 1876 void ChromeLauncherControllerImpl::OnDisplayConfigurationChanged() { | 1722 void ChromeLauncherControllerImpl::OnDisplayConfigurationChanged() { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1906 if (index == -1) | 1752 if (index == -1) |
| 1907 continue; | 1753 continue; |
| 1908 ash::ShelfItem item = model_->items()[index]; | 1754 ash::ShelfItem item = model_->items()[index]; |
| 1909 item.image = image; | 1755 item.image = image; |
| 1910 if (arc_deferred_launcher_) | 1756 if (arc_deferred_launcher_) |
| 1911 arc_deferred_launcher_->MaybeApplySpinningEffect(id, &item.image); | 1757 arc_deferred_launcher_->MaybeApplySpinningEffect(id, &item.image); |
| 1912 model_->Set(index, item); | 1758 model_->Set(index, item); |
| 1913 // It's possible we're waiting on more than one item, so don't break. | 1759 // It's possible we're waiting on more than one item, so don't break. |
| 1914 } | 1760 } |
| 1915 } | 1761 } |
| OLD | NEW |