123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/shelf/shelf_controller.h"
- #include <memory>
- #include "ash/constants/ash_pref_names.h"
- #include "ash/public/cpp/message_center/arc_notification_constants.h"
- #include "ash/public/cpp/shelf_item_delegate.h"
- #include "ash/public/cpp/shelf_prefs.h"
- #include "ash/root_window_controller.h"
- #include "ash/session/session_controller_impl.h"
- #include "ash/shelf/launcher_nudge_controller.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shell.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "ash/wm/tablet_mode/tablet_mode_controller.h"
- #include "base/bind.h"
- #include "chromeos/strings/grit/chromeos_strings.h"
- #include "components/pref_registry/pref_registry_syncable.h"
- #include "components/prefs/pref_change_registrar.h"
- #include "components/prefs/pref_registry_simple.h"
- #include "components/prefs/pref_service.h"
- #include "components/services/app_service/public/cpp/app_registry_cache_wrapper.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/display/display.h"
- #include "ui/display/screen.h"
- namespace ash {
- namespace {
- // Returns the Shelf instance for the display with the given |display_id|.
- Shelf* GetShelfForDisplay(int64_t display_id) {
- // The controller may be null for invalid ids or for displays being removed.
- RootWindowController* root_window_controller =
- Shell::GetRootWindowControllerWithDisplayId(display_id);
- return root_window_controller ? root_window_controller->shelf() : nullptr;
- }
- // Set each Shelf's auto-hide behavior from the per-display pref.
- void SetShelfAutoHideFromPrefs() {
- // TODO(jamescook): The session state check should not be necessary, but
- // otherwise this wrongly tries to set the alignment on a secondary display
- // during login before the ShelfLockingManager is created.
- SessionControllerImpl* session_controller =
- Shell::Get()->session_controller();
- PrefService* prefs = session_controller->GetLastActiveUserPrefService();
- if (!prefs || !session_controller->IsActiveUserSessionStarted())
- return;
- for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
- auto value = GetShelfAutoHideBehaviorPref(prefs, display.id());
- // Don't show the shelf in app mode.
- if (session_controller->IsRunningInAppMode())
- value = ShelfAutoHideBehavior::kAlwaysHidden;
- if (Shelf* shelf = GetShelfForDisplay(display.id()))
- shelf->SetAutoHideBehavior(value);
- }
- }
- // Set each Shelf's alignment from the per-display pref.
- void SetShelfAlignmentFromPrefs() {
- // TODO(jamescook): The session state check should not be necessary, but
- // otherwise this wrongly tries to set the alignment on a secondary display
- // during login before the ShelfLockingManager is created.
- SessionControllerImpl* session_controller =
- Shell::Get()->session_controller();
- PrefService* prefs = session_controller->GetLastActiveUserPrefService();
- if (!prefs || !session_controller->IsActiveUserSessionStarted())
- return;
- for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
- if (Shelf* shelf = GetShelfForDisplay(display.id()))
- shelf->SetAlignment(GetShelfAlignmentPref(prefs, display.id()));
- }
- }
- void UpdateShelfVisibility() {
- for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
- if (Shelf* shelf = GetShelfForDisplay(display.id()))
- shelf->UpdateVisibilityState();
- }
- }
- // Set each Shelf's auto-hide behavior and alignment from the per-display prefs.
- void SetShelfBehaviorsFromPrefs() {
- SetShelfAutoHideFromPrefs();
- // The shelf should always be bottom-aligned in tablet mode; alignment is
- // assigned from prefs when tablet mode is exited.
- if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
- return;
- }
- SetShelfAlignmentFromPrefs();
- }
- } // namespace
- ShelfController::ShelfController() {
- ShelfModel::SetInstance(&model_);
- Shell::Get()->session_controller()->AddObserver(this);
- Shell::Get()->tablet_mode_controller()->AddObserver(this);
- Shell::Get()->window_tree_host_manager()->AddObserver(this);
- model_.AddObserver(this);
- }
- ShelfController::~ShelfController() {
- model_.DestroyItemDelegates();
- }
- void ShelfController::Init() {
- launcher_nudge_controller_ = std::make_unique<LauncherNudgeController>();
- }
- void ShelfController::Shutdown() {
- model_.RemoveObserver(this);
- Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
- Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
- Shell::Get()->session_controller()->RemoveObserver(this);
- }
- // static
- void ShelfController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
- // These prefs are public for ChromeShelfController's OnIsSyncingChanged.
- // See the pref names definitions for explanations of the synced, local, and
- // per-display behaviors.
- registry->RegisterStringPref(
- prefs::kShelfAutoHideBehavior, kShelfAutoHideBehaviorNever,
- user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
- registry->RegisterStringPref(prefs::kShelfAutoHideBehaviorLocal,
- std::string());
- registry->RegisterStringPref(
- prefs::kShelfAlignment, kShelfAlignmentBottom,
- user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
- registry->RegisterStringPref(prefs::kShelfAlignmentLocal, std::string());
- registry->RegisterDictionaryPref(prefs::kShelfPreferences);
- LauncherNudgeController::RegisterProfilePrefs(registry);
- }
- void ShelfController::OnActiveUserSessionChanged(const AccountId& account_id) {
- if (model_.in_shelf_party())
- model_.ToggleShelfParty();
- }
- void ShelfController::OnSessionStateChanged(
- session_manager::SessionState state) {
- if (model_.in_shelf_party())
- model_.ToggleShelfParty();
- }
- void ShelfController::OnActiveUserPrefServiceChanged(
- PrefService* pref_service) {
- SetShelfBehaviorsFromPrefs();
- pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
- pref_change_registrar_->Init(pref_service);
- pref_change_registrar_->Add(prefs::kShelfAlignmentLocal,
- base::BindRepeating(&SetShelfAlignmentFromPrefs));
- pref_change_registrar_->Add(prefs::kShelfAutoHideBehaviorLocal,
- base::BindRepeating(&SetShelfAutoHideFromPrefs));
- pref_change_registrar_->Add(prefs::kShelfPreferences,
- base::BindRepeating(&SetShelfBehaviorsFromPrefs));
- pref_change_registrar_->Add(
- prefs::kAppNotificationBadgingEnabled,
- base::BindRepeating(&ShelfController::UpdateAppNotificationBadging,
- base::Unretained(this)));
- // Observe AppRegistryCache for the current active account to get
- // notification updates.
- AccountId account_id =
- Shell::Get()->session_controller()->GetActiveAccountId();
- cache_ = apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id);
- Observe(cache_);
- // Resetting the recorded pref forces the next call to
- // UpdateAppNotificationBadging() to update notification badging for every
- // app item.
- notification_badging_pref_enabled_.reset();
- // Update the notification badge indicator for all apps. This will also
- // ensure that apps have the correct notification badge value for the
- // multiprofile case when switching between users.
- UpdateAppNotificationBadging();
- }
- void ShelfController::OnTabletModeStarted() {
- // Do nothing when running in app mode.
- if (Shell::Get()->session_controller()->IsRunningInAppMode())
- return;
- // Force the shelf to be visible and to be bottom aligned in tablet mode; the
- // prefs are restored on exit.
- for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
- if (Shelf* shelf = GetShelfForDisplay(display.id())) {
- // Only animate into tablet mode if the shelf alignment will not change.
- if (shelf->IsHorizontalAlignment())
- shelf->set_is_tablet_mode_animation_running(true);
- shelf->SetAlignment(ShelfAlignment::kBottom);
- }
- }
- }
- void ShelfController::OnTabletModeEnded() {
- // Do nothing when running in app mode.
- if (Shell::Get()->session_controller()->IsRunningInAppMode())
- return;
- SetShelfBehaviorsFromPrefs();
- // Only animate out of tablet mode if the shelf alignment will not change.
- for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
- if (Shelf* shelf = GetShelfForDisplay(display.id())) {
- if (shelf->IsHorizontalAlignment())
- shelf->set_is_tablet_mode_animation_running(true);
- }
- }
- }
- void ShelfController::OnDisplayConfigurationChanged() {
- // Update the alignment and auto-hide state from prefs, because a display may
- // have been added, or the display ids for existing shelf instances may have
- // changed. See https://crbug.com/748291
- SetShelfBehaviorsFromPrefs();
- // Update shelf visibility to adapt to display changes. For instance shelf
- // should be hidden on secondary display during inactive session states.
- UpdateShelfVisibility();
- }
- void ShelfController::OnAppUpdate(const apps::AppUpdate& update) {
- if (update.HasBadgeChanged() &&
- notification_badging_pref_enabled_.value_or(false)) {
- bool has_badge = update.HasBadge().value_or(false);
- model_.UpdateItemNotification(update.AppId(), has_badge);
- }
- }
- void ShelfController::OnAppRegistryCacheWillBeDestroyed(
- apps::AppRegistryCache* cache) {
- Observe(nullptr);
- }
- void ShelfController::ShelfItemAdded(int index) {
- if (!cache_ || !notification_badging_pref_enabled_.value_or(false))
- return;
- auto app_id = model_.items()[index].id.app_id;
- // Update the notification badge indicator for the newly added shelf item.
- cache_->ForOneApp(app_id, [this](const apps::AppUpdate& update) {
- bool has_badge = update.HasBadge().value_or(false);
- model_.UpdateItemNotification(update.AppId(), has_badge);
- });
- }
- void ShelfController::UpdateAppNotificationBadging() {
- bool new_badging_enabled = pref_change_registrar_
- ? pref_change_registrar_->prefs()->GetBoolean(
- prefs::kAppNotificationBadgingEnabled)
- : false;
- if (notification_badging_pref_enabled_.has_value() &&
- notification_badging_pref_enabled_.value() == new_badging_enabled) {
- return;
- }
- notification_badging_pref_enabled_ = new_badging_enabled;
- if (cache_) {
- cache_->ForEachApp([this](const apps::AppUpdate& update) {
- // Set the app notification badge hidden when the pref is disabled.
- bool has_badge = notification_badging_pref_enabled_.value()
- ? update.HasBadge().value_or(false)
- : false;
- model_.UpdateItemNotification(update.AppId(), has_badge);
- });
- }
- }
- } // namespace ash
|