Commit 90efb7a4 authored by Matthew Mourgos's avatar Matthew Mourgos Committed by Commit Bot

CrOS Shelf: Add and use pref for app notification badging

This change adds a syncable pref for app notification badging that can
be toggled in the notification quick settings.

When the pref is changed, all app badges in the shelf and app list are
updated. The badges are hidden when the pref is disabled.

Bug: 1080827, 1122723
Change-Id: Icd3ff5562e768cfc8e07c9173263c326f1e66d67
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2366295
Commit-Queue: Matthew Mourgos <mmourgos@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804501}
parent 17a59040
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_features.h"
#include "chromeos/constants/chromeos_pref_names.h" #include "chromeos/constants/chromeos_pref_names.h"
#include "components/pref_registry/pref_registry_syncable.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_registry_simple.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/services/app_service/public/cpp/app_registry_cache_wrapper.h" #include "components/services/app_service/public/cpp/app_registry_cache_wrapper.h"
...@@ -503,7 +504,8 @@ bool AppListControllerImpl::IsVisible( ...@@ -503,7 +504,8 @@ bool AppListControllerImpl::IsVisible(
void AppListControllerImpl::OnAppListItemAdded(AppListItem* item) { void AppListControllerImpl::OnAppListItemAdded(AppListItem* item) {
client_->OnItemAdded(profile_id_, item->CloneMetadata()); client_->OnItemAdded(profile_id_, item->CloneMetadata());
if (is_notification_indicator_enabled_ && cache_) { if (is_notification_indicator_enabled_ && cache_ &&
notification_badging_pref_enabled_.value_or(false)) {
// Update the notification badge indicator for the newly added app list // Update the notification badge indicator for the newly added app list
// item. // item.
cache_->ForOneApp(item->id(), [item](const apps::AppUpdate& update) { cache_->ForOneApp(item->id(), [item](const apps::AppUpdate& update) {
...@@ -513,8 +515,16 @@ void AppListControllerImpl::OnAppListItemAdded(AppListItem* item) { ...@@ -513,8 +515,16 @@ void AppListControllerImpl::OnAppListItemAdded(AppListItem* item) {
} }
void AppListControllerImpl::OnActiveUserPrefServiceChanged( void AppListControllerImpl::OnActiveUserPrefServiceChanged(
PrefService* /* pref_service */) { PrefService* pref_service) {
if (is_notification_indicator_enabled_) { if (is_notification_indicator_enabled_) {
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(pref_service);
pref_change_registrar_->Add(
prefs::kAppNotificationBadgingEnabled,
base::BindRepeating(&AppListControllerImpl::UpdateAppBadging,
base::Unretained(this)));
// Observe AppRegistryCache for the current active account to get // Observe AppRegistryCache for the current active account to get
// notification updates. // notification updates.
AccountId account_id = AccountId account_id =
...@@ -523,12 +533,10 @@ void AppListControllerImpl::OnActiveUserPrefServiceChanged( ...@@ -523,12 +533,10 @@ void AppListControllerImpl::OnActiveUserPrefServiceChanged(
apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id); apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id);
Observe(cache_); Observe(cache_);
if (cache_) { // Resetting the recorded pref forces the next call to UpdateAppBadging()
// Update the notification badge indicator for all apps in the app list. // to update notification badging for every app item.
cache_->ForEachApp([this](const apps::AppUpdate& update) { notification_badging_pref_enabled_.reset();
UpdateItemNotificationBadge(update.AppId(), update.HasBadge()); UpdateAppBadging();
});
}
} }
if (!IsTabletMode()) { if (!IsTabletMode()) {
...@@ -1839,7 +1847,8 @@ gfx::Rect AppListControllerImpl::GetInitialAppListItemScreenBoundsForWindow( ...@@ -1839,7 +1847,8 @@ gfx::Rect AppListControllerImpl::GetInitialAppListItemScreenBoundsForWindow(
} }
void AppListControllerImpl::OnAppUpdate(const apps::AppUpdate& update) { void AppListControllerImpl::OnAppUpdate(const apps::AppUpdate& update) {
if (update.HasBadgeChanged()) { if (update.HasBadgeChanged() &&
notification_badging_pref_enabled_.value_or(false)) {
UpdateItemNotificationBadge(update.AppId(), update.HasBadge()); UpdateItemNotificationBadge(update.AppId(), update.HasBadge());
} }
} }
...@@ -1874,4 +1883,29 @@ void AppListControllerImpl::UpdateItemNotificationBadge( ...@@ -1874,4 +1883,29 @@ void AppListControllerImpl::UpdateItemNotificationBadge(
item->UpdateBadge(has_badge == apps::mojom::OptionalBool::kTrue); item->UpdateBadge(has_badge == apps::mojom::OptionalBool::kTrue);
} }
void AppListControllerImpl::UpdateAppBadging() {
DCHECK(pref_change_registrar_);
PrefService* prefs = pref_change_registrar_->prefs();
bool new_badging_enabled =
prefs->GetBoolean(prefs::kAppNotificationBadgingEnabled);
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.
apps::mojom::OptionalBool has_badge =
notification_badging_pref_enabled_.value() &&
(update.HasBadge() == apps::mojom::OptionalBool::kTrue)
? apps::mojom::OptionalBool::kTrue
: apps::mojom::OptionalBool::kFalse;
UpdateItemNotificationBadge(update.AppId(), has_badge);
});
}
}
} // namespace ash } // namespace ash
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "ui/aura/window_observer.h" #include "ui/aura/window_observer.h"
#include "ui/display/types/display_constants.h" #include "ui/display/types/display_constants.h"
class PrefChangeRegistrar;
class PrefRegistrySimple; class PrefRegistrySimple;
namespace ui { namespace ui {
...@@ -393,6 +394,10 @@ class ASH_EXPORT AppListControllerImpl ...@@ -393,6 +394,10 @@ class ASH_EXPORT AppListControllerImpl
void UpdateItemNotificationBadge(const std::string& app_id, void UpdateItemNotificationBadge(const std::string& app_id,
apps::mojom::OptionalBool has_badge); apps::mojom::OptionalBool has_badge);
// Checks the notification badging pref and then updates whether a
// notification badge is shown for each AppListItem.
void UpdateAppBadging();
// Whether the home launcher is // Whether the home launcher is
// * being shown (either through an animation or a drag) // * being shown (either through an animation or a drag)
// * being hidden (either through an animation or a drag) // * being hidden (either through an animation or a drag)
...@@ -477,6 +482,12 @@ class ASH_EXPORT AppListControllerImpl ...@@ -477,6 +482,12 @@ class ASH_EXPORT AppListControllerImpl
// Whether the notification indicator flag is enabled. // Whether the notification indicator flag is enabled.
const bool is_notification_indicator_enabled_; const bool is_notification_indicator_enabled_;
// Observes user profile prefs for the app list.
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
// Whether the pref for notification badging is enabled.
base::Optional<bool> notification_badging_pref_enabled_;
DISALLOW_COPY_AND_ASSIGN(AppListControllerImpl); DISALLOW_COPY_AND_ASSIGN(AppListControllerImpl);
}; };
......
...@@ -91,8 +91,12 @@ void AppListItem::SetNameAndShortName(const std::string& name, ...@@ -91,8 +91,12 @@ void AppListItem::SetNameAndShortName(const std::string& name,
} }
void AppListItem::UpdateBadge(bool has_badge) { void AppListItem::UpdateBadge(bool has_badge) {
if (has_notification_badge_ == has_badge)
return;
has_notification_badge_ = has_badge;
for (auto& observer : observers_) { for (auto& observer : observers_) {
observer.ItemBadgeVisibilityChanged(has_badge); observer.ItemBadgeVisibilityChanged();
} }
} }
......
...@@ -86,6 +86,8 @@ class APP_LIST_MODEL_EXPORT AppListItem { ...@@ -86,6 +86,8 @@ class APP_LIST_MODEL_EXPORT AppListItem {
} }
bool is_page_break() const { return metadata_->is_page_break; } bool is_page_break() const { return metadata_->is_page_break; }
bool has_notification_badge() const { return has_notification_badge_; }
protected: protected:
// Subclasses also have mutable access to the metadata ptr. // Subclasses also have mutable access to the metadata ptr.
AppListItemMetadata* metadata() { return metadata_.get(); } AppListItemMetadata* metadata() { return metadata_.get(); }
...@@ -135,6 +137,9 @@ class APP_LIST_MODEL_EXPORT AppListItem { ...@@ -135,6 +137,9 @@ class APP_LIST_MODEL_EXPORT AppListItem {
// A shortened name for the item, used for display. // A shortened name for the item, used for display.
std::string short_name_; std::string short_name_;
// Whether this item currently has a notification badge that should be shown.
bool has_notification_badge_ = false;
base::ObserverList<AppListItemObserver>::Unchecked observers_; base::ObserverList<AppListItemObserver>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(AppListItem); DISALLOW_COPY_AND_ASSIGN(AppListItem);
......
...@@ -21,7 +21,7 @@ class APP_LIST_MODEL_EXPORT AppListItemObserver { ...@@ -21,7 +21,7 @@ class APP_LIST_MODEL_EXPORT AppListItemObserver {
virtual void ItemNameChanged() {} virtual void ItemNameChanged() {}
// Invoked when the item's notification badge visibility is changed. // Invoked when the item's notification badge visibility is changed.
virtual void ItemBadgeVisibilityChanged(bool is_badge_visible) {} virtual void ItemBadgeVisibilityChanged() {}
// Invoked when the item is about to be destroyed. // Invoked when the item is about to be destroyed.
virtual void ItemBeingDestroyed() {} virtual void ItemBeingDestroyed() {}
......
...@@ -363,7 +363,7 @@ AppListItemView::AppListItemView(AppsGridView* apps_grid_view, ...@@ -363,7 +363,7 @@ AppListItemView::AppListItemView(AppsGridView* apps_grid_view,
std::make_unique<AppNotificationIndicatorView>(kDefaultIndicatorColor)); std::make_unique<AppNotificationIndicatorView>(kDefaultIndicatorColor));
notification_indicator_->SetPaintToLayer(); notification_indicator_->SetPaintToLayer();
notification_indicator_->layer()->SetFillsBoundsOpaquely(false); notification_indicator_->layer()->SetFillsBoundsOpaquely(false);
notification_indicator_->SetVisible(false); notification_indicator_->SetVisible(item->has_notification_badge());
} }
title_ = AddChildView(std::move(title)); title_ = AddChildView(std::move(title));
...@@ -1117,9 +1117,9 @@ void AppListItemView::ItemNameChanged() { ...@@ -1117,9 +1117,9 @@ void AppListItemView::ItemNameChanged() {
base::UTF8ToUTF16(item_weak_->name())); base::UTF8ToUTF16(item_weak_->name()));
} }
void AppListItemView::ItemBadgeVisibilityChanged(bool is_badge_visible) { void AppListItemView::ItemBadgeVisibilityChanged() {
if (is_notification_indicator_enabled_ && notification_indicator_ && icon_) if (is_notification_indicator_enabled_ && notification_indicator_ && icon_)
notification_indicator_->SetVisible(is_badge_visible); notification_indicator_->SetVisible(item_weak_->has_notification_badge());
} }
void AppListItemView::ItemBeingDestroyed() { void AppListItemView::ItemBeingDestroyed() {
......
...@@ -228,7 +228,7 @@ class APP_LIST_EXPORT AppListItemView : public views::Button, ...@@ -228,7 +228,7 @@ class APP_LIST_EXPORT AppListItemView : public views::Button,
// AppListItemObserver overrides: // AppListItemObserver overrides:
void ItemIconChanged(AppListConfigType config_type) override; void ItemIconChanged(AppListConfigType config_type) override;
void ItemNameChanged() override; void ItemNameChanged() override;
void ItemBadgeVisibilityChanged(bool is_badge_visible) override; void ItemBadgeVisibilityChanged() override;
void ItemBeingDestroyed() override; void ItemBeingDestroyed() override;
// ui::ImplicitAnimationObserver: // ui::ImplicitAnimationObserver:
......
...@@ -583,6 +583,11 @@ const char kDarkModeEnabled[] = "cros.system.dark_mode_enabled"; ...@@ -583,6 +583,11 @@ const char kDarkModeEnabled[] = "cros.system.dark_mode_enabled";
// background color will be calculated based on extracted wallpaper color. // background color will be calculated based on extracted wallpaper color.
const char kColorModeThemed[] = "cros.system.color_mode_themed"; const char kColorModeThemed[] = "cros.system.color_mode_themed";
// A boolean pref that indicates whether app badging is shown in launcher and
// shelf.
const char kAppNotificationBadgingEnabled[] =
"ash.app_notification_badging_enabled";
// NOTE: New prefs should start with the "ash." prefix. Existing prefs moved // NOTE: New prefs should start with the "ash." prefix. Existing prefs moved
// into this file should not be renamed, since they may be synced. // into this file should not be renamed, since they may be synced.
......
...@@ -210,6 +210,8 @@ ASH_PUBLIC_EXPORT extern const char kMultipasteNudges[]; ...@@ -210,6 +210,8 @@ ASH_PUBLIC_EXPORT extern const char kMultipasteNudges[];
ASH_PUBLIC_EXPORT extern const char kDarkModeEnabled[]; ASH_PUBLIC_EXPORT extern const char kDarkModeEnabled[];
ASH_PUBLIC_EXPORT extern const char kColorModeThemed[]; ASH_PUBLIC_EXPORT extern const char kColorModeThemed[];
ASH_PUBLIC_EXPORT extern const char kAppNotificationBadgingEnabled[];
} // namespace prefs } // namespace prefs
} // namespace ash } // namespace ash
......
...@@ -151,24 +151,27 @@ void ShelfController::OnActiveUserPrefServiceChanged( ...@@ -151,24 +151,27 @@ void ShelfController::OnActiveUserPrefServiceChanged(
base::BindRepeating(&SetShelfBehaviorsFromPrefs)); base::BindRepeating(&SetShelfBehaviorsFromPrefs));
if (is_notification_indicator_enabled_) { if (is_notification_indicator_enabled_) {
pref_change_registrar_->Add(
prefs::kAppNotificationBadgingEnabled,
base::BindRepeating(&ShelfController::UpdateAppBadging,
base::Unretained(this)));
// Observe AppRegistryCache for the current active account to get // Observe AppRegistryCache for the current active account to get
// notification updates. // notification updates.
AccountId account_id = AccountId account_id =
Shell::Get()->session_controller()->GetActiveAccountId(); Shell::Get()->session_controller()->GetActiveAccountId();
cache_ = cache_ =
apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id); apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id);
Observe(cache_); Observe(cache_);
if (cache_) { // Resetting the recorded pref forces the next call to UpdateAppBadging()
// Update the notification badge indicator for all apps. This will also // to update notification badging for every app item.
// ensure that apps have the correct notification badge value for the notification_badging_pref_enabled_.reset();
// multiprofile case when switching between users.
cache_->ForEachApp([this](const apps::AppUpdate& update) { // Update the notification badge indicator for all apps. This will also
bool has_badge = update.HasBadge() == apps::mojom::OptionalBool::kTrue; // ensure that apps have the correct notification badge value for the
model_.UpdateItemNotification(update.AppId(), has_badge); // multiprofile case when switching between users.
}); UpdateAppBadging();
}
} }
} }
...@@ -218,7 +221,8 @@ void ShelfController::OnDisplayConfigurationChanged() { ...@@ -218,7 +221,8 @@ void ShelfController::OnDisplayConfigurationChanged() {
} }
void ShelfController::OnAppUpdate(const apps::AppUpdate& update) { void ShelfController::OnAppUpdate(const apps::AppUpdate& update) {
if (update.HasBadgeChanged()) { if (update.HasBadgeChanged() &&
notification_badging_pref_enabled_.value_or(false)) {
bool has_badge = update.HasBadge() == apps::mojom::OptionalBool::kTrue; bool has_badge = update.HasBadge() == apps::mojom::OptionalBool::kTrue;
model_.UpdateItemNotification(update.AppId(), has_badge); model_.UpdateItemNotification(update.AppId(), has_badge);
} }
...@@ -230,7 +234,8 @@ void ShelfController::OnAppRegistryCacheWillBeDestroyed( ...@@ -230,7 +234,8 @@ void ShelfController::OnAppRegistryCacheWillBeDestroyed(
} }
void ShelfController::ShelfItemAdded(int index) { void ShelfController::ShelfItemAdded(int index) {
if (!is_notification_indicator_enabled_ || !cache_) if (!cache_ || !is_notification_indicator_enabled_ ||
!notification_badging_pref_enabled_.value_or(false))
return; return;
auto app_id = model_.items()[index].id.app_id; auto app_id = model_.items()[index].id.app_id;
...@@ -242,4 +247,29 @@ void ShelfController::ShelfItemAdded(int index) { ...@@ -242,4 +247,29 @@ void ShelfController::ShelfItemAdded(int index) {
}); });
} }
void ShelfController::UpdateAppBadging() {
DCHECK(pref_change_registrar_);
PrefService* prefs = pref_change_registrar_->prefs();
bool new_badging_enabled =
prefs->GetBoolean(prefs::kAppNotificationBadgingEnabled);
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() == apps::mojom::OptionalBool::kTrue)
: false;
model_.UpdateItemNotification(update.AppId(), has_badge);
});
}
}
} // namespace ash } // namespace ash
...@@ -60,12 +60,18 @@ class ASH_EXPORT ShelfController : public SessionObserver, ...@@ -60,12 +60,18 @@ class ASH_EXPORT ShelfController : public SessionObserver,
// ShelfModelObserver: // ShelfModelObserver:
void ShelfItemAdded(int index) override; void ShelfItemAdded(int index) override;
// Updates whether an app badge is shown for the shelf items in the model.
void UpdateAppBadging();
// The shelf model shared by all shelf instances. // The shelf model shared by all shelf instances.
ShelfModel model_; ShelfModel model_;
// Whether notification indicators are enabled for app icons in the shelf. // Whether notification indicators are enabled for app icons in the shelf.
const bool is_notification_indicator_enabled_; const bool is_notification_indicator_enabled_;
// Whether the pref for notification badging is enabled.
base::Optional<bool> notification_badging_pref_enabled_;
// Observes user profile prefs for the shelf. // Observes user profile prefs for the shelf.
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
......
...@@ -42,6 +42,9 @@ void MessageCenterController::RegisterProfilePrefs( ...@@ -42,6 +42,9 @@ void MessageCenterController::RegisterProfilePrefs(
prefs::kMessageCenterLockScreenMode, prefs::kMessageCenterLockScreenMode,
prefs::kMessageCenterLockScreenModeHide, prefs::kMessageCenterLockScreenModeHide,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
registry->RegisterBooleanPref(
prefs::kAppNotificationBadgingEnabled, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
} }
namespace { namespace {
......
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/public/cpp/notifier_metadata.h" #include "ash/public/cpp/notifier_metadata.h"
#include "ash/public/cpp/notifier_settings_controller.h" #include "ash/public/cpp/notifier_settings_controller.h"
#include "ash/resources/vector_icons/vector_icons.h" #include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h" #include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h" #include "ash/style/ash_color_provider.h"
...@@ -26,6 +28,7 @@ ...@@ -26,6 +28,7 @@
#include "base/optional.h" #include "base/optional.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "components/prefs/pref_service.h"
#include "skia/ext/image_operations.h" #include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_enums.mojom.h"
...@@ -466,6 +469,15 @@ NotifierSettingsView::NotifierSettingsView() { ...@@ -466,6 +469,15 @@ NotifierSettingsView::NotifierSettingsView() {
TrayPopupUtils::CreateToggleButton( TrayPopupUtils::CreateToggleButton(
this, IDS_ASH_MESSAGE_CENTER_APP_BADGING_BUTTON_TOOLTIP)); this, IDS_ASH_MESSAGE_CENTER_APP_BADGING_BUTTON_TOOLTIP));
app_badging_toggle_ = app_badging_toggle.get(); app_badging_toggle_ = app_badging_toggle.get();
SessionControllerImpl* session_controller =
Shell::Get()->session_controller();
PrefService* prefs = session_controller->GetLastActiveUserPrefService();
if (prefs) {
app_badging_toggle_->SetIsOn(
prefs->GetBoolean(prefs::kAppNotificationBadgingEnabled));
}
auto app_badging_view = CreateToggleButtonRow( auto app_badging_view = CreateToggleButtonRow(
std::move(app_badging_icon), std::move(app_badging_label), std::move(app_badging_icon), std::move(app_badging_label),
std::move(app_badging_toggle)); std::move(app_badging_toggle));
...@@ -659,8 +671,13 @@ bool NotifierSettingsView::OnMouseWheel(const ui::MouseWheelEvent& event) { ...@@ -659,8 +671,13 @@ bool NotifierSettingsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
void NotifierSettingsView::ButtonPressed(views::Button* sender, void NotifierSettingsView::ButtonPressed(views::Button* sender,
const ui::Event& event) { const ui::Event& event) {
if (sender == app_badging_toggle_) { if (sender == app_badging_toggle_) {
// TODO(tengs): Call the appropriate controller to toggle app badging once SessionControllerImpl* session_controller =
// it is available. Shell::Get()->session_controller();
PrefService* prefs = session_controller->GetLastActiveUserPrefService();
if (prefs) {
prefs->SetBoolean(prefs::kAppNotificationBadgingEnabled,
app_badging_toggle_->GetIsOn());
}
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment