Chromium Code Reviews| Index: chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc |
| diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc |
| index e3730c451ebaee4772d38795e9ca2caa2b7508e5..cc93df9b62e1f55b75f55dfe9151437d96598233 100644 |
| --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc |
| +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc |
| @@ -16,11 +16,14 @@ |
| #include "base/values.h" |
| #include "chrome/browser/defaults.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| +#include "chrome/browser/extensions/pending_extension_manager.h" |
| #include "chrome/browser/prefs/incognito_mode_prefs.h" |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/browser/prefs/scoped_user_pref_update.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| +#include "chrome/browser/sync/profile_sync_service.h" |
| +#include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/ui/ash/chrome_launcher_prefs.h" |
| #include "chrome/browser/ui/ash/extension_utils.h" |
| #include "chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h" |
| @@ -49,6 +52,15 @@ |
| using extensions::Extension; |
| +namespace { |
| + |
| +const int kMaxLoadingPlaceholders = 4; |
| + |
| +// Max loading animation time in milliseconds. |
| +const int kMaxLoadingTimeMs = 60 * 1000; |
| + |
| +} // namespace |
| + |
| // ChromeLauncherController::Item ---------------------------------------------- |
| ChromeLauncherController::Item::Item() |
| @@ -68,7 +80,8 @@ ChromeLauncherController::ChromeLauncherController(Profile* profile, |
| ash::LauncherModel* model) |
| : model_(model), |
| profile_(profile), |
| - activation_client_(NULL) { |
| + activation_client_(NULL), |
| + observed_sync_service_(NULL) { |
| if (!profile_) { |
| // Use the original profile as on chromeos we may get a temporary off the |
| // record profile. |
| @@ -90,6 +103,15 @@ ChromeLauncherController::ChromeLauncherController(Profile* profile, |
| pref_change_registrar_.Add(prefs::kPinnedLauncherApps, this); |
| pref_change_registrar_.Add(prefs::kShelfAlignment, this); |
| pref_change_registrar_.Add(prefs::kShelfAutoHideBehavior, this); |
| + |
| + if (!IsLoggedInAsGuest()) { |
| + observed_sync_service_ = |
| + ProfileSyncServiceFactory::GetForProfile(profile_); |
| + if (observed_sync_service_) { |
| + observed_sync_service_->AddObserver(this); |
| + StartLoadingUI(); |
| + } |
| + } |
| } |
| ChromeLauncherController::~ChromeLauncherController() { |
| @@ -111,6 +133,9 @@ ChromeLauncherController::~ChromeLauncherController() { |
| if (ash::Shell::HasInstance()) |
| ash::Shell::GetInstance()->RemoveShellObserver(this); |
| + |
| + if (observed_sync_service_) |
| + observed_sync_service_->RemoveObserver(this); |
| } |
| void ChromeLauncherController::Init() { |
| @@ -263,11 +288,6 @@ void ChromeLauncherController::Open(ash::LauncherID id, int event_flags) { |
| ash::wm::ActivateWindow(controller->window()); |
| } else { |
| DCHECK_EQ(TYPE_APP, id_to_item_map_[id].item_type); |
| - |
| - // Do nothing for pending app shortcut. |
| - if (GetItemStatus(id) == ash::STATUS_IS_PENDING) |
| - return; |
| - |
| OpenAppID(id_to_item_map_[id].app_id, event_flags); |
| } |
| } |
| @@ -620,18 +640,15 @@ void ChromeLauncherController::Observe( |
| switch (type) { |
| case chrome::NOTIFICATION_EXTENSION_LOADED: { |
| UpdateAppLaunchersFromPref(); |
| + CheckAppSync(); |
| break; |
| } |
| case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
| const content::Details<extensions::UnloadedExtensionInfo> unload_info( |
| details); |
| const Extension* extension = unload_info->extension; |
| - if (IsAppPinned(extension->id())) { |
| - if (unload_info->reason == extension_misc::UNLOAD_REASON_UPDATE) |
| - MarkAppPending(extension->id()); |
| - else |
| - DoUnpinAppsWithID(extension->id()); |
| - } |
| + if (IsAppPinned(extension->id())) |
| + DoUnpinAppsWithID(extension->id()); |
| break; |
| } |
| case chrome::NOTIFICATION_PREF_CHANGED: { |
| @@ -743,6 +760,11 @@ void ChromeLauncherController::OnShelfAlignmentChanged() { |
| profile_->GetPrefs()->SetString(prefs::kShelfAlignment, pref_value); |
| } |
| +void ChromeLauncherController::OnStateChanged() { |
| + DCHECK(observed_sync_service_); |
| + CheckAppSync(); |
| +} |
| + |
| void ChromeLauncherController::PersistPinnedState() { |
| // It is a coding error to call PersistPinnedState() if the pinned apps are |
| // not user-editable. The code should check earlier and not perform any |
| @@ -799,18 +821,6 @@ ash::LauncherItemStatus ChromeLauncherController::GetItemStatus( |
| return item.status; |
| } |
| -void ChromeLauncherController::MarkAppPending(const std::string& app_id) { |
| - for (IDToItemMap::const_iterator i = id_to_item_map_.begin(); |
| - i != id_to_item_map_.end(); ++i) { |
| - if (i->second.item_type == TYPE_APP && i->second.app_id == app_id) { |
| - if (GetItemStatus(i->first) == ash::STATUS_CLOSED) |
| - SetItemStatus(i->first, ash::STATUS_IS_PENDING); |
| - |
| - break; |
| - } |
| - } |
| -} |
| - |
| void ChromeLauncherController::DoPinAppWithID(const std::string& app_id) { |
| // If there is an item, do nothing and return. |
| if (IsAppPinned(app_id)) |
| @@ -868,13 +878,6 @@ void ChromeLauncherController::UpdateAppLaunchersFromPref() { |
| IDToItemMap::const_iterator entry(id_to_item_map_.find(item.id)); |
| if (entry != id_to_item_map_.end() && |
| entry->second.app_id == *pref_app_id) { |
| - // Current item will be kept. Reset its pending state and ensure |
| - // its icon is loaded since it has to be valid to be in |pinned_apps|. |
| - if (item.status == ash::STATUS_IS_PENDING) { |
| - SetItemStatus(item.id, ash::STATUS_CLOSED); |
| - app_icon_loader_->FetchImage(*pref_app_id); |
| - } |
| - |
| ++pref_app_id; |
| break; |
| } else { |
| @@ -971,28 +974,76 @@ ash::LauncherID ChromeLauncherController::InsertAppLauncherItem( |
| } |
| item.is_incognito = false; |
| item.image = Extension::GetDefaultIcon(true); |
| - if (item.type == ash::TYPE_APP_SHORTCUT && |
| - !app_tab_helper_->IsValidID(app_id)) { |
| - item.status = ash::STATUS_IS_PENDING; |
| - } else { |
| - TabContents* active_tab = GetLastActiveTabContents(app_id); |
| - if (active_tab) { |
| - Browser* browser = browser::FindBrowserWithWebContents( |
| - active_tab->web_contents()); |
| - DCHECK(browser); |
| - if (browser->window()->IsActive()) |
| - status = ash::STATUS_ACTIVE; |
| - else |
| - status = ash::STATUS_RUNNING; |
| - } |
| - item.status = status; |
| + |
| + TabContents* active_tab = GetLastActiveTabContents(app_id); |
| + if (active_tab) { |
| + Browser* browser = browser::FindBrowserWithWebContents( |
| + active_tab->web_contents()); |
| + DCHECK(browser); |
| + if (browser->window()->IsActive()) |
| + status = ash::STATUS_ACTIVE; |
| + else |
| + status = ash::STATUS_RUNNING; |
| + } |
| + item.status = status; |
| + |
| + // Removes an app placeholder for added app shortcut. This needs to be done |
| + // before adding the shortcut to avoid unnecessary sliding animations. |
| + if (item.type == ash::TYPE_APP_SHORTCUT && !app_placeholders_.empty()) { |
| + ash::LauncherID id = app_placeholders_.front(); |
| + app_placeholders_.pop_front(); |
| + model_->RemoveItemAt(model_->ItemIndexByID(id)); |
| } |
| + |
| model_->AddAt(index, item); |
| if (!controller || controller->type() != |
| BrowserLauncherItemController::TYPE_EXTENSION_PANEL) { |
| - if (item.status != ash::STATUS_IS_PENDING) |
| - app_icon_loader_->FetchImage(app_id); |
| + app_icon_loader_->FetchImage(app_id); |
| } |
| + |
| return id; |
| } |
| + |
| +void ChromeLauncherController::CheckAppSync() { |
| + if (!observed_sync_service_) |
| + return; |
| + |
| + const bool synced = observed_sync_service_->ShouldPushChanges(); |
| + const bool has_pending_extension = profile_->GetExtensionService()-> |
| + pending_extension_manager()->HasPendingExtensionFromSync(); |
| + |
| + if (synced && !has_pending_extension) |
| + StopLoadingUI(); |
| +} |
| + |
| +void ChromeLauncherController::StartLoadingUI() { |
| + DCHECK(!loading_timer_.IsRunning()); |
| + loading_timer_.Start( |
| + FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kMaxLoadingTimeMs), |
| + this, &ChromeLauncherController::StopLoadingUI); |
| + |
| + for (int i = 0; i < kMaxLoadingPlaceholders; ++i) { |
|
sky
2012/08/15 20:52:36
Do we unconditionally add kMaxLoadingPlaceholders
xiyuan
2012/08/15 21:36:03
I am doing this because StartLoadingUI is called b
|
| + ash::LauncherID id = model_->next_id(); |
| + app_placeholders_.push_back(id); |
| + |
| + ash::LauncherItem item; |
| + item.type = ash::TYPE_APP_PLACEHOLDER; |
| + item.is_incognito = false; |
| + model_->Add(item); |
| + } |
| +} |
| + |
| +void ChromeLauncherController::StopLoadingUI() { |
| + loading_timer_.Stop(); |
| + observed_sync_service_->RemoveObserver(this); |
| + observed_sync_service_ = NULL; |
| + |
| + while (!app_placeholders_.empty()) { |
| + ash::LauncherID id = app_placeholders_.front(); |
| + app_placeholders_.pop_front(); |
| + |
| + model_->RemoveItemAt(model_->ItemIndexByID(id)); |
| + } |
| +} |