| 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 442f2e83c1abc8272e9877722f593d6fd6a78de7..973ded6f0b4a767ca7225c6b96b79833b965b9c7 100644
|
| --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
|
| +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
|
| @@ -4,14 +4,286 @@
|
|
|
| #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
|
|
|
| +#include <vector>
|
| +
|
| #include "ash/ash_switches.h"
|
| +#include "ash/launcher/launcher.h"
|
| +#include "ash/launcher/launcher_model.h"
|
| +#include "ash/launcher/launcher_util.h"
|
| +#include "ash/root_window_controller.h"
|
| +#include "ash/shelf/shelf_layout_manager.h"
|
| +#include "ash/shelf/shelf_widget.h"
|
| +#include "ash/shell.h"
|
| +#include "ash/wm/window_util.h"
|
| #include "base/command_line.h"
|
| -#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
|
| -#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/app_mode/app_mode_utils.h"
|
| +#include "chrome/browser/chrome_notification_types.h"
|
| +#include "chrome/browser/defaults.h"
|
| +#include "chrome/browser/extensions/app_icon_loader_impl.h"
|
| +#include "chrome/browser/extensions/extension_service.h"
|
| +#include "chrome/browser/extensions/extension_system.h"
|
| +#include "chrome/browser/favicon/favicon_tab_helper.h"
|
| +#include "chrome/browser/prefs/incognito_mode_prefs.h"
|
| +#include "chrome/browser/prefs/pref_service_syncable.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/ui/ash/app_sync_ui_state.h"
|
| +#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
|
| +#include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
|
| +#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
|
| +#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
|
| +#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
|
| +#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
|
| +#include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
|
| +#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
|
| +#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
|
| +#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
|
| +#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
|
| +#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
|
| +#include "chrome/browser/ui/browser.h"
|
| +#include "chrome/browser/ui/browser_commands.h"
|
| +#include "chrome/browser/ui/browser_finder.h"
|
| +#include "chrome/browser/ui/browser_list.h"
|
| +#include "chrome/browser/ui/browser_tabstrip.h"
|
| +#include "chrome/browser/ui/browser_window.h"
|
| +#include "chrome/browser/ui/extensions/application_launch.h"
|
| +#include "chrome/browser/ui/extensions/extension_enable_flow.h"
|
| +#include "chrome/browser/ui/host_desktop.h"
|
| +#include "chrome/browser/ui/tabs/tab_strip_model.h"
|
| +#include "chrome/browser/web_applications/web_app.h"
|
| +#include "chrome/common/chrome_switches.h"
|
| +#include "chrome/common/extensions/extension.h"
|
| +#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
|
| +#include "chrome/common/pref_names.h"
|
| +#include "chrome/common/url_constants.h"
|
| +#include "content/public/browser/navigation_entry.h"
|
| +#include "content/public/browser/notification_registrar.h"
|
| +#include "content/public/browser/notification_service.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "extensions/common/extension_resource.h"
|
| +#include "extensions/common/url_pattern.h"
|
| +#include "grit/ash_resources.h"
|
| +#include "grit/chromium_strings.h"
|
| +#include "grit/generated_resources.h"
|
| +#include "grit/theme_resources.h"
|
| +#include "grit/ui_resources.h"
|
| +#include "ui/aura/root_window.h"
|
| +#include "ui/aura/window.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/views/corewm/window_animations.h"
|
| +
|
| +#if defined(OS_CHROMEOS)
|
| +#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h"
|
| +#endif
|
| +
|
| +using extensions::Extension;
|
| +using extension_misc::kGmailAppId;
|
| +using content::WebContents;
|
|
|
| -// statics
|
| +// static
|
| ChromeLauncherController* ChromeLauncherController::instance_ = NULL;
|
|
|
| +namespace {
|
| +
|
| +std::string GetPrefKeyForRootWindow(aura::RootWindow* root_window) {
|
| + gfx::Display display = gfx::Screen::GetScreenFor(
|
| + root_window)->GetDisplayNearestWindow(root_window);
|
| + DCHECK(display.is_valid());
|
| +
|
| + return base::Int64ToString(display.id());
|
| +}
|
| +
|
| +void UpdatePerDisplayPref(PrefService* pref_service,
|
| + aura::RootWindow* root_window,
|
| + const char* pref_key,
|
| + const std::string& value) {
|
| + std::string key = GetPrefKeyForRootWindow(root_window);
|
| + if (key.empty())
|
| + return;
|
| +
|
| + DictionaryPrefUpdate update(pref_service, prefs::kShelfPreferences);
|
| + base::DictionaryValue* shelf_prefs = update.Get();
|
| + base::DictionaryValue* prefs = NULL;
|
| + if (!shelf_prefs->GetDictionary(key, &prefs)) {
|
| + prefs = new base::DictionaryValue();
|
| + shelf_prefs->Set(key, prefs);
|
| + }
|
| + prefs->SetStringWithoutPathExpansion(pref_key, value);
|
| +}
|
| +
|
| +// Returns a pref value in |pref_service| for the display of |root_window|. The
|
| +// pref value is stored in |local_path| and |path|, but |pref_service| may have
|
| +// per-display preferences and the value can be specified by policy. Here is
|
| +// the priority:
|
| +// * A value managed by policy. This is a single value that applies to all
|
| +// displays.
|
| +// * A user-set value for the specified display.
|
| +// * A user-set value in |local_path| or |path|, if no per-display settings are
|
| +// ever specified (see http://crbug.com/173719 for why). |local_path| is
|
| +// preferred. See comment in |kShelfAlignment| as to why we consider two
|
| +// prefs and why |local_path| is preferred.
|
| +// * A value recommended by policy. This is a single value that applies to all
|
| +// root windows.
|
| +// * The default value for |local_path| if the value is not recommended by
|
| +// policy.
|
| +std::string GetPrefForRootWindow(PrefService* pref_service,
|
| + aura::RootWindow* root_window,
|
| + const char* local_path,
|
| + const char* path) {
|
| + const PrefService::Preference* local_pref =
|
| + pref_service->FindPreference(local_path);
|
| + const std::string value(pref_service->GetString(local_path));
|
| + if (local_pref->IsManaged())
|
| + return value;
|
| +
|
| + std::string pref_key = GetPrefKeyForRootWindow(root_window);
|
| + bool has_per_display_prefs = false;
|
| + if (!pref_key.empty()) {
|
| + const base::DictionaryValue* shelf_prefs = pref_service->GetDictionary(
|
| + prefs::kShelfPreferences);
|
| + const base::DictionaryValue* display_pref = NULL;
|
| + std::string per_display_value;
|
| + if (shelf_prefs->GetDictionary(pref_key, &display_pref) &&
|
| + display_pref->GetString(path, &per_display_value))
|
| + return per_display_value;
|
| +
|
| + // If the pref for the specified display is not found, scan the whole prefs
|
| + // and check if the prefs for other display is already specified.
|
| + std::string unused_value;
|
| + for (base::DictionaryValue::Iterator iter(*shelf_prefs);
|
| + !iter.IsAtEnd(); iter.Advance()) {
|
| + const base::DictionaryValue* display_pref = NULL;
|
| + if (iter.value().GetAsDictionary(&display_pref) &&
|
| + display_pref->GetString(path, &unused_value)) {
|
| + has_per_display_prefs = true;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (local_pref->IsRecommended() || !has_per_display_prefs)
|
| + return value;
|
| +
|
| + const base::Value* default_value =
|
| + pref_service->GetDefaultPrefValue(local_path);
|
| + std::string default_string;
|
| + default_value->GetAsString(&default_string);
|
| + return default_string;
|
| +}
|
| +
|
| +// If prefs have synced and no user-set value exists at |local_path|, the value
|
| +// from |synced_path| is copied to |local_path|.
|
| +void MaybePropagatePrefToLocal(PrefServiceSyncable* pref_service,
|
| + const char* local_path,
|
| + const char* synced_path) {
|
| + if (!pref_service->FindPreference(local_path)->HasUserSetting() &&
|
| + pref_service->IsSyncing()) {
|
| + // First time the user is using this machine, propagate from remote to
|
| + // local.
|
| + pref_service->SetString(local_path, pref_service->GetString(synced_path));
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ChromeLauncherController::ChromeLauncherController(
|
| + Profile* profile,
|
| + ash::LauncherModel* model)
|
| + : model_(model),
|
| + profile_(profile),
|
| + app_sync_ui_state_(NULL),
|
| + ignore_persist_pinned_state_change_(false) {
|
| + if (!profile_) {
|
| + // Use the original profile as on chromeos we may get a temporary off the
|
| + // record profile.
|
| + profile_ = ProfileManager::GetDefaultProfile()->GetOriginalProfile();
|
| +
|
| + app_sync_ui_state_ = AppSyncUIState::Get(profile_);
|
| + if (app_sync_ui_state_)
|
| + app_sync_ui_state_->AddObserver(this);
|
| + }
|
| +
|
| + model_->AddObserver(this);
|
| + BrowserList::AddObserver(this);
|
| + // Right now ash::Shell isn't created for tests.
|
| + // TODO(mukai): Allows it to observe display change and write tests.
|
| + if (ash::Shell::HasInstance())
|
| + ash::Shell::GetInstance()->display_controller()->AddObserver(this);
|
| + // TODO(stevenjb): Find a better owner for shell_window_controller_?
|
| + shell_window_controller_.reset(new ShellWindowLauncherController(this));
|
| + app_tab_helper_.reset(new LauncherAppTabHelper(profile_));
|
| + app_icon_loader_.reset(new extensions::AppIconLoaderImpl(
|
| + profile_, extension_misc::EXTENSION_ICON_SMALL, this));
|
| +
|
| + notification_registrar_.Add(this,
|
| + chrome::NOTIFICATION_EXTENSION_LOADED,
|
| + content::Source<Profile>(profile_));
|
| + notification_registrar_.Add(this,
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED,
|
| + content::Source<Profile>(profile_));
|
| + pref_change_registrar_.Init(profile_->GetPrefs());
|
| + pref_change_registrar_.Add(
|
| + prefs::kPinnedLauncherApps,
|
| + base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
|
| + base::Unretained(this)));
|
| + pref_change_registrar_.Add(
|
| + prefs::kShelfAlignmentLocal,
|
| + base::Bind(&ChromeLauncherController::SetShelfAlignmentFromPrefs,
|
| + base::Unretained(this)));
|
| + pref_change_registrar_.Add(
|
| + prefs::kShelfAutoHideBehaviorLocal,
|
| + base::Bind(&ChromeLauncherController::
|
| + SetShelfAutoHideBehaviorFromPrefs,
|
| + base::Unretained(this)));
|
| + pref_change_registrar_.Add(
|
| + prefs::kShelfPreferences,
|
| + base::Bind(&ChromeLauncherController::SetShelfBehaviorsFromPrefs,
|
| + base::Unretained(this)));
|
| +}
|
| +
|
| +ChromeLauncherController::~ChromeLauncherController() {
|
| + // Reset the shell window controller here since it has a weak pointer to this.
|
| + shell_window_controller_.reset();
|
| +
|
| + for (std::set<ash::Launcher*>::iterator iter = launchers_.begin();
|
| + iter != launchers_.end();
|
| + ++iter)
|
| + (*iter)->shelf_widget()->shelf_layout_manager()->RemoveObserver(this);
|
| +
|
| + model_->RemoveObserver(this);
|
| + BrowserList::RemoveObserver(this);
|
| + if (ash::Shell::HasInstance())
|
| + ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
|
| + for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
|
| + i != id_to_item_controller_map_.end(); ++i) {
|
| + i->second->OnRemoved();
|
| + // TODO(skuhne): After getting rid of the old launcher, get also rid of the
|
| + // BrowserLauncherItemController (since it is only used for activation
|
| + // tracking at that point.
|
| + int index = model_->ItemIndexByID(i->first);
|
| + // A "browser proxy" is not known to the model and this removal does
|
| + // therefore not need to be propagated to the model.
|
| + if (index != -1 &&
|
| + model_->items()[index].type != ash::TYPE_BROWSER_SHORTCUT)
|
| + model_->RemoveItemAt(index);
|
| + }
|
| +
|
| + if (ash::Shell::HasInstance())
|
| + ash::Shell::GetInstance()->RemoveShellObserver(this);
|
| +
|
| + if (app_sync_ui_state_)
|
| + app_sync_ui_state_->RemoveObserver(this);
|
| +
|
| + PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
|
| +
|
| + if (instance_ == this)
|
| + instance_ = NULL;
|
| +}
|
| +
|
| // static
|
| ChromeLauncherController* ChromeLauncherController::CreateInstance(
|
| Profile* profile,
|
| @@ -19,21 +291,1368 @@ ChromeLauncherController* ChromeLauncherController::CreateInstance(
|
| // We do not check here for re-creation of the ChromeLauncherController since
|
| // it appears that it might be intentional that the ChromeLauncherController
|
| // can be re-created.
|
| - if (!CommandLine::ForCurrentProcess()->HasSwitch(
|
| - ash::switches::kAshDisablePerAppLauncher))
|
| - instance_ = new ChromeLauncherControllerPerApp(profile, model);
|
| - else
|
| - instance_ = new ChromeLauncherControllerPerBrowser(profile, model);
|
| + instance_ = new ChromeLauncherController(profile, model);
|
| return instance_;
|
| }
|
|
|
| -ChromeLauncherController::~ChromeLauncherController() {
|
| - if (instance_ == this)
|
| - instance_ = NULL;
|
| +void ChromeLauncherController::Init() {
|
| + UpdateAppLaunchersFromPref();
|
| + CreateBrowserShortcutLauncherItem();
|
| +
|
| + // TODO(sky): update unit test so that this test isn't necessary.
|
| + if (ash::Shell::HasInstance()) {
|
| + SetShelfAutoHideBehaviorFromPrefs();
|
| + SetShelfAlignmentFromPrefs();
|
| + PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
|
| + if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() ||
|
| + !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)->
|
| + HasUserSetting()) {
|
| + // This causes OnIsSyncingChanged to be called when the value of
|
| + // PrefService::IsSyncing() changes.
|
| + prefs->AddObserver(this);
|
| + }
|
| + ash::Shell::GetInstance()->AddShellObserver(this);
|
| + }
|
| +}
|
| +
|
| +ash::LauncherID ChromeLauncherController::CreateAppLauncherItem(
|
| + LauncherItemController* controller,
|
| + const std::string& app_id,
|
| + ash::LauncherItemStatus status) {
|
| + CHECK(controller);
|
| + int index = 0;
|
| + // Panels are inserted on the left so as not to push all existing panels over.
|
| + if (controller->GetLauncherItemType() != ash::TYPE_APP_PANEL) {
|
| + index = model_->item_count();
|
| + // For the alternate shelf layout increment the index (after the app icon)
|
| + if (ash::switches::UseAlternateShelfLayout())
|
| + ++index;
|
| + }
|
| + return InsertAppLauncherItem(controller,
|
| + app_id,
|
| + status,
|
| + index,
|
| + controller->GetLauncherItemType());
|
| +}
|
| +
|
| +void ChromeLauncherController::SetItemStatus(
|
| + ash::LauncherID id,
|
| + ash::LauncherItemStatus status) {
|
| + int index = model_->ItemIndexByID(id);
|
| + // Since ordinary browser windows are not registered, we might get a negative
|
| + // index here.
|
| + if (index >= 0) {
|
| + ash::LauncherItem item = model_->items()[index];
|
| + item.status = status;
|
| + model_->Set(index, item);
|
| +
|
| + if (model_->items()[index].type == ash::TYPE_BROWSER_SHORTCUT)
|
| + return;
|
| + }
|
| + UpdateBrowserItemStatus();
|
| +}
|
| +
|
| +void ChromeLauncherController::SetItemController(
|
| + ash::LauncherID id,
|
| + LauncherItemController* controller) {
|
| + CHECK(controller);
|
| + IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
|
| + CHECK(iter != id_to_item_controller_map_.end());
|
| + iter->second->OnRemoved();
|
| + iter->second = controller;
|
| + controller->set_launcher_id(id);
|
| +}
|
| +
|
| +void ChromeLauncherController::CloseLauncherItem(ash::LauncherID id) {
|
| + CHECK(id);
|
| + if (IsPinned(id)) {
|
| + // Create a new shortcut controller.
|
| + IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
|
| + CHECK(iter != id_to_item_controller_map_.end());
|
| + SetItemStatus(id, ash::STATUS_CLOSED);
|
| + std::string app_id = iter->second->app_id();
|
| + iter->second->OnRemoved();
|
| + iter->second = new AppShortcutLauncherItemController(app_id, this);
|
| + iter->second->set_launcher_id(id);
|
| + } else {
|
| + LauncherItemClosed(id);
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::Pin(ash::LauncherID id) {
|
| + DCHECK(HasItemController(id));
|
| +
|
| + int index = model_->ItemIndexByID(id);
|
| + DCHECK_GE(index, 0);
|
| +
|
| + ash::LauncherItem item = model_->items()[index];
|
| +
|
| + if (item.type == ash::TYPE_PLATFORM_APP ||
|
| + item.type == ash::TYPE_WINDOWED_APP) {
|
| + item.type = ash::TYPE_APP_SHORTCUT;
|
| + model_->Set(index, item);
|
| + } else if (item.type != ash::TYPE_APP_SHORTCUT) {
|
| + return;
|
| + }
|
| +
|
| + if (CanPin())
|
| + PersistPinnedState();
|
| +}
|
| +
|
| +void ChromeLauncherController::Unpin(ash::LauncherID id) {
|
| + DCHECK(HasItemController(id));
|
| +
|
| + LauncherItemController* controller = id_to_item_controller_map_[id];
|
| + if (controller->type() == LauncherItemController::TYPE_APP) {
|
| + int index = model_->ItemIndexByID(id);
|
| + DCHECK_GE(index, 0);
|
| + ash::LauncherItem item = model_->items()[index];
|
| + item.type = ash::TYPE_PLATFORM_APP;
|
| + model_->Set(index, item);
|
| + } else {
|
| + // Prevent the removal of items upon unpin if it is locked by a running
|
| + // windowed V1 app.
|
| + if (!controller->locked()) {
|
| + LauncherItemClosed(id);
|
| + } else {
|
| + int index = model_->ItemIndexByID(id);
|
| + DCHECK_GE(index, 0);
|
| + ash::LauncherItem item = model_->items()[index];
|
| + item.type = ash::TYPE_WINDOWED_APP;
|
| + model_->Set(index, item);
|
| + }
|
| + }
|
| + if (CanPin())
|
| + PersistPinnedState();
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsPinned(ash::LauncherID id) {
|
| + int index = model_->ItemIndexByID(id);
|
| + if (index < 0)
|
| + return false;
|
| + ash::LauncherItemType type = model_->items()[index].type;
|
| + return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT);
|
| +}
|
| +
|
| +void ChromeLauncherController::TogglePinned(ash::LauncherID id) {
|
| + if (!HasItemController(id))
|
| + return; // May happen if item closed with menu open.
|
| +
|
| + if (IsPinned(id))
|
| + Unpin(id);
|
| + else
|
| + Pin(id);
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsPinnable(ash::LauncherID id) const {
|
| + int index = model_->ItemIndexByID(id);
|
| + if (index == -1)
|
| + return false;
|
| +
|
| + ash::LauncherItemType type = model_->items()[index].type;
|
| + return ((type == ash::TYPE_APP_SHORTCUT ||
|
| + type == ash::TYPE_PLATFORM_APP ||
|
| + type == ash::TYPE_WINDOWED_APP) &&
|
| + CanPin());
|
| +}
|
| +
|
| +void ChromeLauncherController::LockV1AppWithID(
|
| + const std::string& app_id) {
|
| + ash::LauncherID id = GetLauncherIDForAppID(app_id);
|
| + if (!IsPinned(id) && !IsWindowedAppInLauncher(app_id)) {
|
| + CreateAppShortcutLauncherItemWithType(app_id,
|
| + model_->item_count(),
|
| + ash::TYPE_WINDOWED_APP);
|
| + id = GetLauncherIDForAppID(app_id);
|
| + }
|
| + CHECK(id);
|
| + id_to_item_controller_map_[id]->lock();
|
| +}
|
| +
|
| +void ChromeLauncherController::UnlockV1AppWithID(
|
| + const std::string& app_id) {
|
| + ash::LauncherID id = GetLauncherIDForAppID(app_id);
|
| + CHECK(IsPinned(id) || IsWindowedAppInLauncher(app_id));
|
| + CHECK(id);
|
| + LauncherItemController* controller = id_to_item_controller_map_[id];
|
| + controller->unlock();
|
| + if (!controller->locked() && !IsPinned(id))
|
| + CloseLauncherItem(id);
|
| +}
|
| +
|
| +void ChromeLauncherController::Launch(ash::LauncherID id,
|
| + int event_flags) {
|
| + if (!HasItemController(id))
|
| + return; // In case invoked from menu and item closed while menu up.
|
| + id_to_item_controller_map_[id]->Launch(event_flags);
|
| +}
|
| +
|
| +void ChromeLauncherController::Close(ash::LauncherID id) {
|
| + if (!HasItemController(id))
|
| + return; // May happen if menu closed.
|
| + id_to_item_controller_map_[id]->Close();
|
| }
|
|
|
| -bool ChromeLauncherController::IsPerAppLauncher() {
|
| - if (!instance_)
|
| +bool ChromeLauncherController::IsOpen(ash::LauncherID id) {
|
| + if (!HasItemController(id))
|
| return false;
|
| - return instance_->GetPerAppInterface() != NULL;
|
| + return id_to_item_controller_map_[id]->IsOpen();
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsPlatformApp(ash::LauncherID id) {
|
| + if (!HasItemController(id))
|
| + return false;
|
| +
|
| + std::string app_id = GetAppIDForLauncherID(id);
|
| + const Extension* extension = GetExtensionForAppID(app_id);
|
| + // An extension can be synced / updated at any time and therefore not be
|
| + // available.
|
| + return extension ? extension->is_platform_app() : false;
|
| +}
|
| +
|
| +void ChromeLauncherController::LaunchApp(const std::string& app_id,
|
| + int event_flags) {
|
| + // |extension| could be NULL when it is being unloaded for updating.
|
| + const Extension* extension = GetExtensionForAppID(app_id);
|
| + if (!extension)
|
| + return;
|
| +
|
| + const ExtensionService* service =
|
| + extensions::ExtensionSystem::Get(profile_)->extension_service();
|
| + if (!service->IsExtensionEnabledForLauncher(app_id)) {
|
| + // Do nothing if there is already a running enable flow.
|
| + if (extension_enable_flow_)
|
| + return;
|
| +
|
| + extension_enable_flow_.reset(
|
| + new ExtensionEnableFlow(profile_, app_id, this));
|
| + extension_enable_flow_->StartForNativeWindow(NULL);
|
| + return;
|
| + }
|
| +
|
| + chrome::OpenApplication(chrome::AppLaunchParams(GetProfileForNewWindows(),
|
| + extension,
|
| + event_flags));
|
| +}
|
| +
|
| +void ChromeLauncherController::ActivateApp(const std::string& app_id,
|
| + int event_flags) {
|
| + // If there is an existing non-shortcut controller for this app, open it.
|
| + ash::LauncherID id = GetLauncherIDForAppID(app_id);
|
| + if (id) {
|
| + LauncherItemController* controller = id_to_item_controller_map_[id];
|
| + controller->Activate();
|
| + return;
|
| + }
|
| +
|
| + // Create a temporary application launcher item and use it to see if there are
|
| + // running instances.
|
| + scoped_ptr<AppShortcutLauncherItemController> app_controller(
|
| + new AppShortcutLauncherItemController(app_id, this));
|
| + if (!app_controller->GetRunningApplications().empty())
|
| + app_controller->Activate();
|
| + else
|
| + LaunchApp(app_id, event_flags);
|
| +}
|
| +
|
| +extensions::ExtensionPrefs::LaunchType
|
| + ChromeLauncherController::GetLaunchType(ash::LauncherID id) {
|
| + DCHECK(HasItemController(id));
|
| +
|
| + const Extension* extension = GetExtensionForAppID(
|
| + id_to_item_controller_map_[id]->app_id());
|
| +
|
| + // An extension can be unloaded/updated/unavailable at any time.
|
| + if (!extension)
|
| + return extensions::ExtensionPrefs::LAUNCH_DEFAULT;
|
| +
|
| + return profile_->GetExtensionService()->extension_prefs()->GetLaunchType(
|
| + extension,
|
| + extensions::ExtensionPrefs::LAUNCH_DEFAULT);
|
| +}
|
| +
|
| +std::string ChromeLauncherController::GetAppID(content::WebContents* tab) {
|
| + return app_tab_helper_->GetAppID(tab);
|
| +}
|
| +
|
| +ash::LauncherID ChromeLauncherController::GetLauncherIDForAppID(
|
| + const std::string& app_id) {
|
| + for (IDToItemControllerMap::const_iterator i =
|
| + id_to_item_controller_map_.begin();
|
| + i != id_to_item_controller_map_.end(); ++i) {
|
| + if (i->second->type() == LauncherItemController::TYPE_APP_PANEL)
|
| + continue; // Don't include panels
|
| + if (i->second->app_id() == app_id)
|
| + return i->first;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +std::string ChromeLauncherController::GetAppIDForLauncherID(
|
| + ash::LauncherID id) {
|
| + CHECK(HasItemController(id));
|
| + return id_to_item_controller_map_[id]->app_id();
|
| +}
|
| +
|
| +void ChromeLauncherController::SetAppImage(const std::string& id,
|
| + const gfx::ImageSkia& image) {
|
| + // TODO: need to get this working for shortcuts.
|
| +
|
| + for (IDToItemControllerMap::const_iterator i =
|
| + id_to_item_controller_map_.begin();
|
| + i != id_to_item_controller_map_.end(); ++i) {
|
| + LauncherItemController* controller = i->second;
|
| + if (controller->app_id() != id)
|
| + continue;
|
| + if (controller->image_set_by_controller())
|
| + continue;
|
| + int index = model_->ItemIndexByID(i->first);
|
| + if (index == -1)
|
| + continue;
|
| + ash::LauncherItem item = model_->items()[index];
|
| + item.image = image;
|
| + model_->Set(index, item);
|
| + // It's possible we're waiting on more than one item, so don't break.
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::OnAutoHideBehaviorChanged(
|
| + aura::RootWindow* root_window,
|
| + ash::ShelfAutoHideBehavior new_behavior) {
|
| + SetShelfAutoHideBehaviorPrefs(new_behavior, root_window);
|
| +}
|
| +
|
| +void ChromeLauncherController::SetLauncherItemImage(
|
| + ash::LauncherID launcher_id,
|
| + const gfx::ImageSkia& image) {
|
| + int index = model_->ItemIndexByID(launcher_id);
|
| + if (index == -1)
|
| + return;
|
| + ash::LauncherItem item = model_->items()[index];
|
| + item.image = image;
|
| + model_->Set(index, item);
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsAppPinned(const std::string& app_id) {
|
| + for (IDToItemControllerMap::const_iterator i =
|
| + id_to_item_controller_map_.begin();
|
| + i != id_to_item_controller_map_.end(); ++i) {
|
| + if (IsPinned(i->first) && i->second->app_id() == app_id)
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsWindowedAppInLauncher(
|
| + const std::string& app_id) {
|
| + int index = model_->ItemIndexByID(GetLauncherIDForAppID(app_id));
|
| + if (index < 0)
|
| + return false;
|
| +
|
| + ash::LauncherItemType type = model_->items()[index].type;
|
| + return type == ash::TYPE_WINDOWED_APP;
|
| +}
|
| +
|
| +void ChromeLauncherController::PinAppWithID(const std::string& app_id) {
|
| + if (CanPin())
|
| + DoPinAppWithID(app_id);
|
| + else
|
| + NOTREACHED();
|
| +}
|
| +
|
| +void ChromeLauncherController::SetLaunchType(
|
| + ash::LauncherID id,
|
| + extensions::ExtensionPrefs::LaunchType launch_type) {
|
| + if (!HasItemController(id))
|
| + return;
|
| +
|
| + profile_->GetExtensionService()->extension_prefs()->SetLaunchType(
|
| + id_to_item_controller_map_[id]->app_id(), launch_type);
|
| +}
|
| +
|
| +void ChromeLauncherController::UnpinAppsWithID(const std::string& app_id) {
|
| + if (CanPin())
|
| + DoUnpinAppsWithID(app_id);
|
| + else
|
| + NOTREACHED();
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsLoggedInAsGuest() {
|
| + return ProfileManager::GetDefaultProfileOrOffTheRecord()->IsOffTheRecord();
|
| +}
|
| +
|
| +void ChromeLauncherController::CreateNewWindow() {
|
| + chrome::NewEmptyWindow(
|
| + GetProfileForNewWindows(), chrome::HOST_DESKTOP_TYPE_ASH);
|
| +}
|
| +
|
| +void ChromeLauncherController::CreateNewIncognitoWindow() {
|
| + chrome::NewEmptyWindow(GetProfileForNewWindows()->GetOffTheRecordProfile(),
|
| + chrome::HOST_DESKTOP_TYPE_ASH);
|
| +}
|
| +
|
| +bool ChromeLauncherController::CanPin() const {
|
| + const PrefService::Preference* pref =
|
| + profile_->GetPrefs()->FindPreference(prefs::kPinnedLauncherApps);
|
| + return pref && pref->IsUserModifiable();
|
| +}
|
| +
|
| +void ChromeLauncherController::PersistPinnedState() {
|
| + if (ignore_persist_pinned_state_change_)
|
| + return;
|
| + // 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
|
| + // modification actions that trigger persisting the state.
|
| + if (!CanPin()) {
|
| + NOTREACHED() << "Can't pin but pinned state being updated";
|
| + return;
|
| + }
|
| +
|
| + // Mutating kPinnedLauncherApps is going to notify us and trigger us to
|
| + // process the change. We don't want that to happen so remove ourselves as a
|
| + // listener.
|
| + pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
|
| + {
|
| + ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
|
| + updater->Clear();
|
| + for (size_t i = 0; i < model_->items().size(); ++i) {
|
| + if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
|
| + ash::LauncherID id = model_->items()[i].id;
|
| + if (HasItemController(id) && IsPinned(id)) {
|
| + base::DictionaryValue* app_value = ash::CreateAppDict(
|
| + id_to_item_controller_map_[id]->app_id());
|
| + if (app_value)
|
| + updater->Append(app_value);
|
| + }
|
| + } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) {
|
| + PersistChromeItemIndex(i);
|
| + }
|
| + }
|
| + }
|
| + pref_change_registrar_.Add(
|
| + prefs::kPinnedLauncherApps,
|
| + base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
|
| + base::Unretained(this)));
|
| +}
|
| +
|
| +ash::LauncherModel* ChromeLauncherController::model() {
|
| + return model_;
|
| +}
|
| +
|
| +Profile* ChromeLauncherController::profile() {
|
| + return profile_;
|
| +}
|
| +
|
| +ash::ShelfAutoHideBehavior ChromeLauncherController::GetShelfAutoHideBehavior(
|
| + aura::RootWindow* root_window) const {
|
| + // Don't show the shelf in app mode.
|
| + if (chrome::IsRunningInAppMode())
|
| + return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
|
| +
|
| + // See comment in |kShelfAlignment| as to why we consider two prefs.
|
| + const std::string behavior_value(
|
| + GetPrefForRootWindow(profile_->GetPrefs(),
|
| + root_window,
|
| + prefs::kShelfAutoHideBehaviorLocal,
|
| + prefs::kShelfAutoHideBehavior));
|
| +
|
| + // Note: To maintain sync compatibility with old images of chrome/chromeos
|
| + // the set of values that may be encountered includes the now-extinct
|
| + // "Default" as well as "Never" and "Always", "Default" should now
|
| + // be treated as "Never" (http://crbug.com/146773).
|
| + if (behavior_value == ash::kShelfAutoHideBehaviorAlways)
|
| + return ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
|
| + return ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER;
|
| +}
|
| +
|
| +bool ChromeLauncherController::CanUserModifyShelfAutoHideBehavior(
|
| + aura::RootWindow* root_window) const {
|
| + return profile_->GetPrefs()->
|
| + FindPreference(prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
|
| +}
|
| +
|
| +void ChromeLauncherController::ToggleShelfAutoHideBehavior(
|
| + aura::RootWindow* root_window) {
|
| + ash::ShelfAutoHideBehavior behavior = GetShelfAutoHideBehavior(root_window) ==
|
| + ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS ?
|
| + ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER :
|
| + ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
|
| + SetShelfAutoHideBehaviorPrefs(behavior, root_window);
|
| + return;
|
| +}
|
| +
|
| +void ChromeLauncherController::RemoveTabFromRunningApp(
|
| + WebContents* tab,
|
| + const std::string& app_id) {
|
| + web_contents_to_app_id_.erase(tab);
|
| + AppIDToWebContentsListMap::iterator i_app_id =
|
| + app_id_to_web_contents_list_.find(app_id);
|
| + if (i_app_id != app_id_to_web_contents_list_.end()) {
|
| + WebContentsList* tab_list = &i_app_id->second;
|
| + tab_list->remove(tab);
|
| + if (tab_list->empty()) {
|
| + app_id_to_web_contents_list_.erase(i_app_id);
|
| + i_app_id = app_id_to_web_contents_list_.end();
|
| + ash::LauncherID id = GetLauncherIDForAppID(app_id);
|
| + if (id)
|
| + SetItemStatus(id, ash::STATUS_CLOSED);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::UpdateAppState(content::WebContents* contents,
|
| + AppState app_state) {
|
| + std::string app_id = GetAppID(contents);
|
| +
|
| + // Check if the gMail app is loaded and it matches the given content.
|
| + // This special treatment is needed to address crbug.com/234268.
|
| + if (app_id.empty() && ContentCanBeHandledByGmailApp(contents))
|
| + app_id = kGmailAppId;
|
| +
|
| + // Check the old |app_id| for a tab. If the contents has changed we need to
|
| + // remove it from the previous app.
|
| + if (web_contents_to_app_id_.find(contents) != web_contents_to_app_id_.end()) {
|
| + std::string last_app_id = web_contents_to_app_id_[contents];
|
| + if (last_app_id != app_id)
|
| + RemoveTabFromRunningApp(contents, last_app_id);
|
| + }
|
| +
|
| + if (app_id.empty()) {
|
| + // Even if there is no application running, we should update the activation
|
| + // state of the associated browser.
|
| + UpdateBrowserItemStatus();
|
| + return;
|
| + }
|
| +
|
| + web_contents_to_app_id_[contents] = app_id;
|
| +
|
| + if (app_state == APP_STATE_REMOVED) {
|
| + // The tab has gone away.
|
| + RemoveTabFromRunningApp(contents, app_id);
|
| + } else {
|
| + WebContentsList& tab_list(app_id_to_web_contents_list_[app_id]);
|
| +
|
| + if (app_state == APP_STATE_INACTIVE) {
|
| + WebContentsList::const_iterator i_tab =
|
| + std::find(tab_list.begin(), tab_list.end(), contents);
|
| + if (i_tab == tab_list.end())
|
| + tab_list.push_back(contents);
|
| + if (i_tab != tab_list.begin()) {
|
| + // Going inactive, but wasn't the front tab, indicating that a new
|
| + // tab has already become active.
|
| + return;
|
| + }
|
| + } else {
|
| + tab_list.remove(contents);
|
| + tab_list.push_front(contents);
|
| + }
|
| + ash::LauncherID id = GetLauncherIDForAppID(app_id);
|
| + if (id) {
|
| + // If the window is active, mark the app as active.
|
| + SetItemStatus(id, app_state == APP_STATE_WINDOW_ACTIVE ?
|
| + ash::STATUS_ACTIVE : ash::STATUS_RUNNING);
|
| + }
|
| + }
|
| + UpdateBrowserItemStatus();
|
| +}
|
| +
|
| +void ChromeLauncherController::SetRefocusURLPatternForTest(ash::LauncherID id,
|
| + const GURL& url) {
|
| + DCHECK(HasItemController(id));
|
| + LauncherItemController* controller = id_to_item_controller_map_[id];
|
| +
|
| + int index = model_->ItemIndexByID(id);
|
| + if (index == -1) {
|
| + NOTREACHED() << "Invalid launcher id";
|
| + return;
|
| + }
|
| +
|
| + ash::LauncherItemType type = model_->items()[index].type;
|
| + if (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_WINDOWED_APP) {
|
| + AppShortcutLauncherItemController* app_controller =
|
| + static_cast<AppShortcutLauncherItemController*>(controller);
|
| + app_controller->set_refocus_url(url);
|
| + } else {
|
| + NOTREACHED() << "Invalid launcher type";
|
| + }
|
| +}
|
| +
|
| +const Extension* ChromeLauncherController::GetExtensionForAppID(
|
| + const std::string& app_id) const {
|
| + // Some unit tests do not have a real extension.
|
| + return (profile_->GetExtensionService()) ?
|
| + profile_->GetExtensionService()->GetInstalledExtension(app_id) : NULL;
|
| +}
|
| +
|
| +void ChromeLauncherController::ActivateWindowOrMinimizeIfActive(
|
| + ui::BaseWindow* window,
|
| + bool allow_minimize) {
|
| + if (window->IsActive() && allow_minimize) {
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kDisableMinimizeOnSecondLauncherItemClick)) {
|
| + AnimateWindow(window->GetNativeWindow(),
|
| + views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
|
| + } else {
|
| + window->Minimize();
|
| + }
|
| + } else {
|
| + window->Show();
|
| + window->Activate();
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::ItemSelected(const ash::LauncherItem& item,
|
| + const ui::Event& event) {
|
| + DCHECK(HasItemController(item.id));
|
| + LauncherItemController* item_controller = id_to_item_controller_map_[item.id];
|
| +#if defined(OS_CHROMEOS)
|
| + if (!item_controller->app_id().empty()) {
|
| + chromeos::default_pinned_apps_field_trial::RecordShelfAppClick(
|
| + item_controller->app_id());
|
| + }
|
| +#endif
|
| + item_controller->Clicked(event);
|
| +}
|
| +
|
| +string16 ChromeLauncherController::GetTitle(const ash::LauncherItem& item) {
|
| + DCHECK(HasItemController(item.id));
|
| + return id_to_item_controller_map_[item.id]->GetTitle();
|
| +}
|
| +
|
| +ui::MenuModel* ChromeLauncherController::CreateContextMenu(
|
| + const ash::LauncherItem& item,
|
| + aura::RootWindow* root_window) {
|
| + return new LauncherContextMenu(this, &item, root_window);
|
| +}
|
| +
|
| +ash::LauncherMenuModel* ChromeLauncherController::CreateApplicationMenu(
|
| + const ash::LauncherItem& item,
|
| + int event_flags) {
|
| + return new LauncherApplicationMenuItemModel(GetApplicationList(item,
|
| + event_flags));
|
| +}
|
| +
|
| +ash::LauncherID ChromeLauncherController::GetIDByWindow(aura::Window* window) {
|
| + int browser_index = ash::launcher::GetBrowserItemIndex(*model_);
|
| + DCHECK_GE(browser_index, 0);
|
| + ash::LauncherID browser_id = model_->items()[browser_index].id;
|
| +
|
| + IDToItemControllerMap::const_iterator i = id_to_item_controller_map_.begin();
|
| + for (; i != id_to_item_controller_map_.end(); ++i) {
|
| + // Since a |window| can be used by multiple applications, an explicit
|
| + // application always gets chosen over the generic browser.
|
| + if (i->first != browser_id && i->second->IsCurrentlyShownInWindow(window))
|
| + return i->first;
|
| + }
|
| +
|
| + if (i == id_to_item_controller_map_.end() &&
|
| + GetBrowserShortcutLauncherItemController()->
|
| + IsCurrentlyShownInWindow(window))
|
| + return browser_id;
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsDraggable(const ash::LauncherItem& item) {
|
| + return (item.type == ash::TYPE_APP_SHORTCUT ||
|
| + item.type == ash::TYPE_WINDOWED_APP) ? CanPin() : true;
|
| +}
|
| +
|
| +bool ChromeLauncherController::ShouldShowTooltip(
|
| + const ash::LauncherItem& item) {
|
| + if (item.type == ash::TYPE_APP_PANEL &&
|
| + id_to_item_controller_map_[item.id]->IsVisible())
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +void ChromeLauncherController::OnLauncherCreated(ash::Launcher* launcher) {
|
| + launchers_.insert(launcher);
|
| + launcher->shelf_widget()->shelf_layout_manager()->AddObserver(this);
|
| +}
|
| +
|
| +void ChromeLauncherController::OnLauncherDestroyed(ash::Launcher* launcher) {
|
| + launchers_.erase(launcher);
|
| + // RemoveObserver is not called here, since by the time this method is called
|
| + // Launcher is already in its destructor.
|
| +}
|
| +
|
| +void ChromeLauncherController::LauncherItemAdded(int index) {
|
| +}
|
| +
|
| +void ChromeLauncherController::LauncherItemRemoved(int index,
|
| + ash::LauncherID id) {
|
| +}
|
| +
|
| +void ChromeLauncherController::LauncherItemMoved(int start_index,
|
| + int target_index) {
|
| + ash::LauncherID id = model_->items()[target_index].id;
|
| + if (HasItemController(id) && IsPinned(id))
|
| + PersistPinnedState();
|
| +}
|
| +
|
| +void ChromeLauncherController::LauncherItemChanged(
|
| + int index,
|
| + const ash::LauncherItem& old_item) {
|
| + ash::LauncherID id = model_->items()[index].id;
|
| + DCHECK(HasItemController(id));
|
| + id_to_item_controller_map_[id]->LauncherItemChanged(index, old_item);
|
| +}
|
| +
|
| +void ChromeLauncherController::LauncherStatusChanged() {
|
| +}
|
| +
|
| +void ChromeLauncherController::Observe(
|
| + int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) {
|
| + switch (type) {
|
| + case chrome::NOTIFICATION_EXTENSION_LOADED: {
|
| + const Extension* extension =
|
| + content::Details<const Extension>(details).ptr();
|
| + if (IsAppPinned(extension->id())) {
|
| + // Clear and re-fetch to ensure icon is up-to-date.
|
| + app_icon_loader_->ClearImage(extension->id());
|
| + app_icon_loader_->FetchImage(extension->id());
|
| + }
|
| +
|
| + UpdateAppLaunchersFromPref();
|
| + break;
|
| + }
|
| + case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
|
| + const content::Details<extensions::UnloadedExtensionInfo>& unload_info(
|
| + details);
|
| + const Extension* extension = unload_info->extension;
|
| + const std::string& id = extension->id();
|
| + // Since we might have windowed apps of this type which might have
|
| + // outstanding locks which needs to be removed.
|
| + if (GetLauncherIDForAppID(id) &&
|
| + unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
|
| + CloseWindowedAppsFromRemovedExtension(id);
|
| + }
|
| +
|
| + if (IsAppPinned(id)) {
|
| + if (unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
|
| + DoUnpinAppsWithID(id);
|
| + app_icon_loader_->ClearImage(id);
|
| + } else {
|
| + app_icon_loader_->UpdateImage(id);
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + NOTREACHED() << "Unexpected notification type=" << type;
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::OnShelfAlignmentChanged(
|
| + aura::RootWindow* root_window) {
|
| + const char* pref_value = NULL;
|
| + switch (ash::Shell::GetInstance()->GetShelfAlignment(root_window)) {
|
| + case ash::SHELF_ALIGNMENT_BOTTOM:
|
| + pref_value = ash::kShelfAlignmentBottom;
|
| + break;
|
| + case ash::SHELF_ALIGNMENT_LEFT:
|
| + pref_value = ash::kShelfAlignmentLeft;
|
| + break;
|
| + case ash::SHELF_ALIGNMENT_RIGHT:
|
| + pref_value = ash::kShelfAlignmentRight;
|
| + break;
|
| + case ash::SHELF_ALIGNMENT_TOP:
|
| + pref_value = ash::kShelfAlignmentTop;
|
| + }
|
| +
|
| + UpdatePerDisplayPref(
|
| + profile_->GetPrefs(), root_window, prefs::kShelfAlignment, pref_value);
|
| +
|
| + if (root_window == ash::Shell::GetPrimaryRootWindow()) {
|
| + // See comment in |kShelfAlignment| about why we have two prefs here.
|
| + profile_->GetPrefs()->SetString(prefs::kShelfAlignmentLocal, pref_value);
|
| + profile_->GetPrefs()->SetString(prefs::kShelfAlignment, pref_value);
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::OnDisplayConfigurationChanging() {
|
| +}
|
| +
|
| +void ChromeLauncherController::OnDisplayConfigurationChanged() {
|
| + SetShelfBehaviorsFromPrefs();
|
| +}
|
| +
|
| +void ChromeLauncherController::OnIsSyncingChanged() {
|
| + PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
|
| + MaybePropagatePrefToLocal(prefs,
|
| + prefs::kShelfAlignmentLocal,
|
| + prefs::kShelfAlignment);
|
| + MaybePropagatePrefToLocal(prefs,
|
| + prefs::kShelfAutoHideBehaviorLocal,
|
| + prefs::kShelfAutoHideBehavior);
|
| +}
|
| +
|
| +void ChromeLauncherController::OnAppSyncUIStatusChanged() {
|
| + if (app_sync_ui_state_->status() == AppSyncUIState::STATUS_SYNCING)
|
| + model_->SetStatus(ash::LauncherModel::STATUS_LOADING);
|
| + else
|
| + model_->SetStatus(ash::LauncherModel::STATUS_NORMAL);
|
| +}
|
| +
|
| +void ChromeLauncherController::ExtensionEnableFlowFinished() {
|
| + LaunchApp(extension_enable_flow_->extension_id(), ui::EF_NONE);
|
| + extension_enable_flow_.reset();
|
| +}
|
| +
|
| +void ChromeLauncherController::ExtensionEnableFlowAborted(bool user_initiated) {
|
| + extension_enable_flow_.reset();
|
| +}
|
| +
|
| +ChromeLauncherAppMenuItems ChromeLauncherController::GetApplicationList(
|
| + const ash::LauncherItem& item,
|
| + int event_flags) {
|
| + // Make sure that there is a controller associated with the id and that the
|
| + // extension itself is a valid application and not a panel.
|
| + if (!HasItemController(item.id) ||
|
| + !GetLauncherIDForAppID(id_to_item_controller_map_[item.id]->app_id()))
|
| + return ChromeLauncherAppMenuItems().Pass();
|
| +
|
| + return id_to_item_controller_map_[item.id]->GetApplicationList(event_flags);
|
| +}
|
| +
|
| +std::vector<content::WebContents*>
|
| +ChromeLauncherController::GetV1ApplicationsFromAppId(std::string app_id) {
|
| + ash::LauncherID id = GetLauncherIDForAppID(app_id);
|
| +
|
| + // If there is no such an item pinned to the launcher, no menu gets created.
|
| + if (id) {
|
| + LauncherItemController* controller = id_to_item_controller_map_[id];
|
| + DCHECK(controller);
|
| + if (controller->type() == LauncherItemController::TYPE_SHORTCUT)
|
| + return GetV1ApplicationsFromController(controller);
|
| + }
|
| + return std::vector<content::WebContents*>();
|
| +}
|
| +
|
| +void ChromeLauncherController::ActivateShellApp(const std::string& app_id,
|
| + int index) {
|
| + ash::LauncherID id = GetLauncherIDForAppID(app_id);
|
| + if (id) {
|
| + LauncherItemController* controller = id_to_item_controller_map_[id];
|
| + if (controller->type() == LauncherItemController::TYPE_APP) {
|
| + ShellWindowLauncherItemController* shell_window_controller =
|
| + static_cast<ShellWindowLauncherItemController*>(controller);
|
| + shell_window_controller->ActivateIndexedApp(index);
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsWebContentHandledByApplication(
|
| + content::WebContents* web_contents,
|
| + const std::string& app_id) {
|
| + if ((web_contents_to_app_id_.find(web_contents) !=
|
| + web_contents_to_app_id_.end()) &&
|
| + (web_contents_to_app_id_[web_contents] == app_id))
|
| + return true;
|
| + return (app_id == kGmailAppId && ContentCanBeHandledByGmailApp(web_contents));
|
| +}
|
| +
|
| +bool ChromeLauncherController::ContentCanBeHandledByGmailApp(
|
| + content::WebContents* web_contents) {
|
| + ash::LauncherID id = GetLauncherIDForAppID(kGmailAppId);
|
| + if (id) {
|
| + const GURL url = web_contents->GetURL();
|
| + // We need to extend the application matching for the gMail app beyond the
|
| + // manifest file's specification. This is required because of the namespace
|
| + // overlap with the offline app ("/mail/mu/").
|
| + if (!MatchPattern(url.path(), "/mail/mu/*") &&
|
| + MatchPattern(url.path(), "/mail/*") &&
|
| + GetExtensionForAppID(kGmailAppId) &&
|
| + GetExtensionForAppID(kGmailAppId)->OverlapsWithOrigin(url))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +gfx::Image ChromeLauncherController::GetAppListIcon(
|
| + content::WebContents* web_contents) const {
|
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance();
|
| + if (IsIncognito(web_contents))
|
| + return rb.GetImageNamed(IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER);
|
| + FaviconTabHelper* favicon_tab_helper =
|
| + FaviconTabHelper::FromWebContents(web_contents);
|
| + gfx::Image result = favicon_tab_helper->GetFavicon();
|
| + if (result.IsEmpty())
|
| + return rb.GetImageNamed(IDR_DEFAULT_FAVICON);
|
| + return result;
|
| +}
|
| +
|
| +string16 ChromeLauncherController::GetAppListTitle(
|
| + content::WebContents* web_contents) const {
|
| + string16 title = web_contents->GetTitle();
|
| + if (!title.empty())
|
| + return title;
|
| + WebContentsToAppIDMap::const_iterator iter =
|
| + web_contents_to_app_id_.find(web_contents);
|
| + if (iter != web_contents_to_app_id_.end()) {
|
| + std::string app_id = iter->second;
|
| + const extensions::Extension* extension = GetExtensionForAppID(app_id);
|
| + if (extension)
|
| + return UTF8ToUTF16(extension->name());
|
| + }
|
| + return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
|
| +}
|
| +
|
| +void ChromeLauncherController::OnBrowserRemoved(Browser* browser) {
|
| + // When called by a unit test it is possible that there is no shell.
|
| + // In that case, the following function should not get called.
|
| + if (ash::Shell::HasInstance())
|
| + UpdateBrowserItemStatus();
|
| +}
|
| +
|
| +ash::LauncherID ChromeLauncherController::CreateAppShortcutLauncherItem(
|
| + const std::string& app_id,
|
| + int index) {
|
| + return CreateAppShortcutLauncherItemWithType(app_id,
|
| + index,
|
| + ash::TYPE_APP_SHORTCUT);
|
| +}
|
| +
|
| +void ChromeLauncherController::SetAppTabHelperForTest(AppTabHelper* helper) {
|
| + app_tab_helper_.reset(helper);
|
| +}
|
| +
|
| +void ChromeLauncherController::SetAppIconLoaderForTest(
|
| + extensions::AppIconLoader* loader) {
|
| + app_icon_loader_.reset(loader);
|
| +}
|
| +
|
| +const std::string& ChromeLauncherController::GetAppIdFromLauncherIdForTest(
|
| + ash::LauncherID id) {
|
| + return id_to_item_controller_map_[id]->app_id();
|
| +}
|
| +
|
| +ash::LauncherID ChromeLauncherController::CreateAppShortcutLauncherItemWithType(
|
| + const std::string& app_id,
|
| + int index,
|
| + ash::LauncherItemType launcher_item_type) {
|
| + AppShortcutLauncherItemController* controller =
|
| + new AppShortcutLauncherItemController(app_id, this);
|
| + ash::LauncherID launcher_id = InsertAppLauncherItem(
|
| + controller, app_id, ash::STATUS_CLOSED, index, launcher_item_type);
|
| + return launcher_id;
|
| +}
|
| +
|
| +void ChromeLauncherController::UpdateBrowserItemStatus() {
|
| + // Determine the new browser's active state and change if necessary.
|
| + size_t browser_index = ash::launcher::GetBrowserItemIndex(*model_);
|
| + DCHECK_GE(browser_index, 0u);
|
| + ash::LauncherItem browser_item = model_->items()[browser_index];
|
| + ash::LauncherItemStatus browser_status = ash::STATUS_CLOSED;
|
| +
|
| + aura::Window* window = ash::wm::GetActiveWindow();
|
| + if (window) {
|
| + // Check if the active browser / tab is a browser which is not an app,
|
| + // a windowed app, a popup or any other item which is not a browser of
|
| + // interest.
|
| + Browser* browser = chrome::FindBrowserWithWindow(window);
|
| + if (IsBrowserRepresentedInBrowserList(browser)) {
|
| + browser_status = ash::STATUS_ACTIVE;
|
| + const ash::LauncherItems& items = model_->items();
|
| + // If another launcher item has claimed to be active, we don't.
|
| + for (size_t i = 0;
|
| + i < items.size() && browser_status == ash::STATUS_ACTIVE; ++i) {
|
| + if (i != browser_index && items[i].status == ash::STATUS_ACTIVE)
|
| + browser_status = ash::STATUS_RUNNING;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (browser_status == ash::STATUS_CLOSED) {
|
| + const BrowserList* ash_browser_list =
|
| + BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
|
| + for (BrowserList::const_reverse_iterator it =
|
| + ash_browser_list->begin_last_active();
|
| + it != ash_browser_list->end_last_active() &&
|
| + browser_status == ash::STATUS_CLOSED; ++it) {
|
| + if (IsBrowserRepresentedInBrowserList(*it))
|
| + browser_status = ash::STATUS_RUNNING;
|
| + }
|
| + }
|
| +
|
| + if (browser_status != browser_item.status) {
|
| + browser_item.status = browser_status;
|
| + model_->Set(browser_index, browser_item);
|
| + }
|
| +}
|
| +
|
| +Profile* ChromeLauncherController::GetProfileForNewWindows() {
|
| + return ProfileManager::GetDefaultProfileOrOffTheRecord();
|
| +}
|
| +
|
| +void ChromeLauncherController::LauncherItemClosed(ash::LauncherID id) {
|
| + IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
|
| + CHECK(iter != id_to_item_controller_map_.end());
|
| + CHECK(iter->second);
|
| + app_icon_loader_->ClearImage(iter->second->app_id());
|
| + iter->second->OnRemoved();
|
| + id_to_item_controller_map_.erase(iter);
|
| + int index = model_->ItemIndexByID(id);
|
| + // A "browser proxy" is not known to the model and this removal does
|
| + // therefore not need to be propagated to the model.
|
| + if (index != -1)
|
| + model_->RemoveItemAt(index);
|
| +}
|
| +
|
| +void ChromeLauncherController::DoPinAppWithID(const std::string& app_id) {
|
| + // If there is an item, do nothing and return.
|
| + if (IsAppPinned(app_id))
|
| + return;
|
| +
|
| + ash::LauncherID launcher_id = GetLauncherIDForAppID(app_id);
|
| + if (launcher_id) {
|
| + // App item exists, pin it
|
| + Pin(launcher_id);
|
| + } else {
|
| + // Otherwise, create a shortcut item for it.
|
| + CreateAppShortcutLauncherItem(app_id, model_->item_count());
|
| + if (CanPin())
|
| + PersistPinnedState();
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::DoUnpinAppsWithID(const std::string& app_id) {
|
| + for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
|
| + i != id_to_item_controller_map_.end(); ) {
|
| + IDToItemControllerMap::iterator current(i);
|
| + ++i;
|
| + if (current->second->app_id() == app_id && IsPinned(current->first))
|
| + Unpin(current->first);
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::UpdateAppLaunchersFromPref() {
|
| + // Construct a vector representation of to-be-pinned apps from the pref.
|
| + std::vector<std::string> pinned_apps;
|
| + int chrome_icon_index = GetChromeIconIndexFromPref();
|
| + int index = 0;
|
| + int max_index = model_->item_count();
|
| + // Using the alternate shelf layout the App Icon should be the first item in
|
| + // the list thus start adding items at slot 1 (instead of slot 0).
|
| + if (ash::switches::UseAlternateShelfLayout()) {
|
| + ++index;
|
| + ++max_index;
|
| + // The alternate shelf layout's icon position will always include the
|
| + // AppLauncher which needs to be subtracted here.
|
| + if (chrome_icon_index > 0)
|
| + --chrome_icon_index;
|
| + }
|
| + const base::ListValue* pinned_apps_pref =
|
| + profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
|
| + for (base::ListValue::const_iterator it(pinned_apps_pref->begin());
|
| + it != pinned_apps_pref->end(); ++it) {
|
| + // To preserve the Chrome icon position, we insert a dummy slot for it - if
|
| + // the model has a Chrome item. While initializing we can come here with no
|
| + // item in which case the count would be 1 or below.
|
| + if (it - pinned_apps_pref->begin() == chrome_icon_index &&
|
| + model_->item_count() > 1) {
|
| + pinned_apps.push_back(extension_misc::kChromeAppId);
|
| + }
|
| +
|
| + DictionaryValue* app = NULL;
|
| + std::string app_id;
|
| + if ((*it)->GetAsDictionary(&app) &&
|
| + app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) &&
|
| + std::find(pinned_apps.begin(), pinned_apps.end(), app_id) ==
|
| + pinned_apps.end() &&
|
| + app_tab_helper_->IsValidID(app_id)) {
|
| + pinned_apps.push_back(app_id);
|
| + }
|
| + }
|
| +
|
| + // Walk the model and |pinned_apps| from the pref lockstep, adding and
|
| + // removing items as necessary. NB: This code uses plain old indexing instead
|
| + // of iterators because of model mutations as part of the loop.
|
| + std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
|
| + for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
|
| + // If the next app launcher according to the pref is present in the model,
|
| + // delete all app launcher entries in between.
|
| + if (*pref_app_id == extension_misc::kChromeAppId ||
|
| + IsAppPinned(*pref_app_id)) {
|
| + for (; index < max_index; ++index) {
|
| + const ash::LauncherItem& item(model_->items()[index]);
|
| + if (item.type != ash::TYPE_APP_SHORTCUT &&
|
| + item.type != ash::TYPE_BROWSER_SHORTCUT)
|
| + continue;
|
| +
|
| + IDToItemControllerMap::const_iterator entry =
|
| + id_to_item_controller_map_.find(item.id);
|
| + if ((extension_misc::kChromeAppId == *pref_app_id &&
|
| + item.type == ash::TYPE_BROWSER_SHORTCUT) ||
|
| + (entry != id_to_item_controller_map_.end() &&
|
| + entry->second->app_id() == *pref_app_id)) {
|
| + ++pref_app_id;
|
| + break;
|
| + } else {
|
| + if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
|
| + // We cannot delete the browser shortcut. As such we move it up by
|
| + // one. To avoid any side effects from our pinned state observer, we
|
| + // do not call the model directly.
|
| + MoveItemWithoutPinnedStateChangeNotification(index, index + 1);
|
| + } else {
|
| + LauncherItemClosed(item.id);
|
| + --max_index;
|
| + }
|
| + --index;
|
| + }
|
| + }
|
| + // If the item wasn't found, that means id_to_item_controller_map_
|
| + // is out of sync.
|
| + DCHECK(index < max_index);
|
| + } else {
|
| + // This app wasn't pinned before, insert a new entry.
|
| + ash::LauncherID id = CreateAppShortcutLauncherItem(*pref_app_id, index);
|
| + index = model_->ItemIndexByID(id);
|
| + ++pref_app_id;
|
| + }
|
| + }
|
| +
|
| + // Remove any trailing existing items.
|
| + while (index < model_->item_count()) {
|
| + const ash::LauncherItem& item(model_->items()[index]);
|
| + if (item.type == ash::TYPE_APP_SHORTCUT)
|
| + LauncherItemClosed(item.id);
|
| + else
|
| + ++index;
|
| + }
|
| +
|
| + // Append unprocessed items from the pref to the end of the model.
|
| + for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
|
| + // Ignore the chrome icon.
|
| + if (*pref_app_id != extension_misc::kChromeAppId)
|
| + DoPinAppWithID(*pref_app_id);
|
| + }
|
| +
|
| +}
|
| +
|
| +void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs(
|
| + ash::ShelfAutoHideBehavior behavior,
|
| + aura::RootWindow* root_window) {
|
| + const char* value = NULL;
|
| + switch (behavior) {
|
| + case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
|
| + value = ash::kShelfAutoHideBehaviorAlways;
|
| + break;
|
| + case ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
|
| + value = ash::kShelfAutoHideBehaviorNever;
|
| + break;
|
| + case ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
|
| + // This one should not be a valid preference option for now. We only want
|
| + // to completely hide it when we run app mode.
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + UpdatePerDisplayPref(
|
| + profile_->GetPrefs(), root_window, prefs::kShelfAutoHideBehavior, value);
|
| +
|
| + if (root_window == ash::Shell::GetPrimaryRootWindow()) {
|
| + // See comment in |kShelfAlignment| about why we have two prefs here.
|
| + profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehaviorLocal, value);
|
| + profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehavior, value);
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::SetShelfAutoHideBehaviorFromPrefs() {
|
| + ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
|
| +
|
| + for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
|
| + iter != root_windows.end(); ++iter) {
|
| + ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
|
| + GetShelfAutoHideBehavior(*iter), *iter);
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::SetShelfAlignmentFromPrefs() {
|
| + if (!ash::ShelfWidget::ShelfAlignmentAllowed())
|
| + return;
|
| +
|
| + ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
|
| +
|
| + for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
|
| + iter != root_windows.end(); ++iter) {
|
| + // See comment in |kShelfAlignment| as to why we consider two prefs.
|
| + const std::string alignment_value(
|
| + GetPrefForRootWindow(profile_->GetPrefs(),
|
| + *iter,
|
| + prefs::kShelfAlignmentLocal,
|
| + prefs::kShelfAlignment));
|
| + ash::ShelfAlignment alignment = ash::SHELF_ALIGNMENT_BOTTOM;
|
| + if (alignment_value == ash::kShelfAlignmentLeft)
|
| + alignment = ash::SHELF_ALIGNMENT_LEFT;
|
| + else if (alignment_value == ash::kShelfAlignmentRight)
|
| + alignment = ash::SHELF_ALIGNMENT_RIGHT;
|
| + else if (alignment_value == ash::kShelfAlignmentTop)
|
| + alignment = ash::SHELF_ALIGNMENT_TOP;
|
| + ash::Shell::GetInstance()->SetShelfAlignment(alignment, *iter);
|
| + }
|
| +}
|
| +
|
| +void ChromeLauncherController::SetShelfBehaviorsFromPrefs() {
|
| + SetShelfAutoHideBehaviorFromPrefs();
|
| + SetShelfAlignmentFromPrefs();
|
| +}
|
| +
|
| +WebContents* ChromeLauncherController::GetLastActiveWebContents(
|
| + const std::string& app_id) {
|
| + AppIDToWebContentsListMap::const_iterator i =
|
| + app_id_to_web_contents_list_.find(app_id);
|
| + if (i == app_id_to_web_contents_list_.end())
|
| + return NULL;
|
| + DCHECK_GT(i->second.size(), 0u);
|
| + return *i->second.begin();
|
| +}
|
| +
|
| +ash::LauncherID ChromeLauncherController::InsertAppLauncherItem(
|
| + LauncherItemController* controller,
|
| + const std::string& app_id,
|
| + ash::LauncherItemStatus status,
|
| + int index,
|
| + ash::LauncherItemType launcher_item_type) {
|
| + ash::LauncherID id = model_->next_id();
|
| + CHECK(!HasItemController(id));
|
| + CHECK(controller);
|
| + id_to_item_controller_map_[id] = controller;
|
| + controller->set_launcher_id(id);
|
| +
|
| + ash::LauncherItem item;
|
| + item.type = launcher_item_type;
|
| + item.is_incognito = false;
|
| + item.image = extensions::IconsInfo::GetDefaultAppIcon();
|
| +
|
| + WebContents* active_tab = GetLastActiveWebContents(app_id);
|
| + if (active_tab) {
|
| + Browser* browser = chrome::FindBrowserWithWebContents(active_tab);
|
| + DCHECK(browser);
|
| + if (browser->window()->IsActive())
|
| + status = ash::STATUS_ACTIVE;
|
| + else
|
| + status = ash::STATUS_RUNNING;
|
| + }
|
| + item.status = status;
|
| +
|
| + model_->AddAt(index, item);
|
| +
|
| + app_icon_loader_->FetchImage(app_id);
|
| +
|
| + return id;
|
| +}
|
| +
|
| +bool ChromeLauncherController::HasItemController(ash::LauncherID id) const {
|
| + return id_to_item_controller_map_.find(id) !=
|
| + id_to_item_controller_map_.end();
|
| +}
|
| +
|
| +std::vector<content::WebContents*>
|
| +ChromeLauncherController::GetV1ApplicationsFromController(
|
| + LauncherItemController* controller) {
|
| + DCHECK(controller->type() == LauncherItemController::TYPE_SHORTCUT);
|
| + AppShortcutLauncherItemController* app_controller =
|
| + static_cast<AppShortcutLauncherItemController*>(controller);
|
| + return app_controller->GetRunningApplications();
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsBrowserRepresentedInBrowserList(
|
| + Browser* browser) {
|
| + return (browser &&
|
| + (browser->is_type_tabbed() ||
|
| + !browser->is_app() ||
|
| + !browser->is_type_popup() ||
|
| + GetLauncherIDForAppID(web_app::GetExtensionIdFromApplicationName(
|
| + browser->app_name())) <= 0));
|
| +}
|
| +
|
| +LauncherItemController*
|
| +ChromeLauncherController::GetBrowserShortcutLauncherItemController() {
|
| + for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
|
| + i != id_to_item_controller_map_.end(); ++i) {
|
| + int index = model_->ItemIndexByID(i->first);
|
| + const ash::LauncherItem& item = model_->items()[index];
|
| + if (item.type == ash::TYPE_BROWSER_SHORTCUT)
|
| + return i->second;
|
| + }
|
| + // LauncerItemController For Browser Shortcut must be existed. If it does not
|
| + // existe create it.
|
| + ash::LauncherID id = CreateBrowserShortcutLauncherItem();
|
| + DCHECK(id_to_item_controller_map_[id]);
|
| + return id_to_item_controller_map_[id];
|
| +}
|
| +
|
| +ash::LauncherID ChromeLauncherController::CreateBrowserShortcutLauncherItem() {
|
| + ash::LauncherItem browser_shortcut;
|
| + browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT;
|
| + browser_shortcut.is_incognito = false;
|
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance();
|
| + browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
|
| + ash::LauncherID id = model_->next_id();
|
| + size_t index = GetChromeIconIndexFromPref();
|
| + model_->AddAt(index, browser_shortcut);
|
| + browser_item_controller_.reset(
|
| + new BrowserShortcutLauncherItemController(this, profile_));
|
| + id_to_item_controller_map_[id] = browser_item_controller_.get();
|
| + id_to_item_controller_map_[id]->set_launcher_id(id);
|
| + return id;
|
| +}
|
| +
|
| +void ChromeLauncherController::PersistChromeItemIndex(int index) {
|
| + profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index);
|
| +}
|
| +
|
| +int ChromeLauncherController::GetChromeIconIndexFromPref() const {
|
| + size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
|
| + const base::ListValue* pinned_apps_pref =
|
| + profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
|
| + if (ash::switches::UseAlternateShelfLayout())
|
| + return std::max(static_cast<size_t>(1),
|
| + std::min(pinned_apps_pref->GetSize() + 1, index));
|
| + return std::max(static_cast<size_t>(0),
|
| + std::min(pinned_apps_pref->GetSize(), index));
|
| +}
|
| +
|
| +bool ChromeLauncherController::IsIncognito(
|
| + content::WebContents* web_contents) const {
|
| + const Profile* profile =
|
| + Profile::FromBrowserContext(web_contents->GetBrowserContext());
|
| + return profile->IsOffTheRecord() && !profile->IsGuestSession();
|
| +}
|
| +
|
| +void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension(
|
| + const std::string& app_id) {
|
| + // This function cannot rely on the controller's enumeration functionality
|
| + // since the extension has already be unloaded.
|
| + const BrowserList* ash_browser_list =
|
| + BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
|
| + std::vector<Browser*> browser_to_close;
|
| + for (BrowserList::const_reverse_iterator
|
| + it = ash_browser_list->begin_last_active();
|
| + it != ash_browser_list->end_last_active(); ++it) {
|
| + Browser* browser = *it;
|
| + if (!browser->is_type_tabbed() &&
|
| + browser->is_type_popup() &&
|
| + browser->is_app() &&
|
| + app_id == web_app::GetExtensionIdFromApplicationName(
|
| + browser->app_name())) {
|
| + browser_to_close.push_back(browser);
|
| + }
|
| + }
|
| + while (!browser_to_close.empty()) {
|
| + TabStripModel* tab_strip = browser_to_close.back()->tab_strip_model();
|
| + tab_strip->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
|
| + browser_to_close.pop_back();
|
| + }
|
| +}
|
| +
|
| +void
|
| +ChromeLauncherController::MoveItemWithoutPinnedStateChangeNotification(
|
| + int source_index, int target_index) {
|
| + base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true);
|
| + model_->Move(source_index, target_index);
|
| }
|
|
|