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 @@
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/constants/chromeos_pref_names.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"
......@@ -503,7 +504,8 @@ bool AppListControllerImpl::IsVisible(
void AppListControllerImpl::OnAppListItemAdded(AppListItem* item) {
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
// item.
cache_->ForOneApp(item->id(), [item](const apps::AppUpdate& update) {
......@@ -513,8 +515,16 @@ void AppListControllerImpl::OnAppListItemAdded(AppListItem* item) {
}
void AppListControllerImpl::OnActiveUserPrefServiceChanged(
PrefService* /* pref_service */) {
PrefService* pref_service) {
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
// notification updates.
AccountId account_id =
......@@ -523,12 +533,10 @@ void AppListControllerImpl::OnActiveUserPrefServiceChanged(
apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id);
Observe(cache_);
if (cache_) {
// Update the notification badge indicator for all apps in the app list.
cache_->ForEachApp([this](const apps::AppUpdate& update) {
UpdateItemNotificationBadge(update.AppId(), update.HasBadge());
});
}
// Resetting the recorded pref forces the next call to UpdateAppBadging()
// to update notification badging for every app item.
notification_badging_pref_enabled_.reset();
UpdateAppBadging();
}
if (!IsTabletMode()) {
......@@ -1839,7 +1847,8 @@ gfx::Rect AppListControllerImpl::GetInitialAppListItemScreenBoundsForWindow(
}
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());
}
}
......@@ -1874,4 +1883,29 @@ void AppListControllerImpl::UpdateItemNotificationBadge(
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
......@@ -37,6 +37,7 @@
#include "ui/aura/window_observer.h"
#include "ui/display/types/display_constants.h"
class PrefChangeRegistrar;
class PrefRegistrySimple;
namespace ui {
......@@ -393,6 +394,10 @@ class ASH_EXPORT AppListControllerImpl
void UpdateItemNotificationBadge(const std::string& app_id,
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
// * being shown (either through an animation or a drag)
// * being hidden (either through an animation or a drag)
......@@ -477,6 +482,12 @@ class ASH_EXPORT AppListControllerImpl
// Whether the notification indicator flag is 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);
};
......
......@@ -91,8 +91,12 @@ void AppListItem::SetNameAndShortName(const std::string& name,
}
void AppListItem::UpdateBadge(bool has_badge) {
if (has_notification_badge_ == has_badge)
return;
has_notification_badge_ = has_badge;
for (auto& observer : observers_) {
observer.ItemBadgeVisibilityChanged(has_badge);
observer.ItemBadgeVisibilityChanged();
}
}
......
......@@ -86,6 +86,8 @@ class APP_LIST_MODEL_EXPORT AppListItem {
}
bool is_page_break() const { return metadata_->is_page_break; }
bool has_notification_badge() const { return has_notification_badge_; }
protected:
// Subclasses also have mutable access to the metadata ptr.
AppListItemMetadata* metadata() { return metadata_.get(); }
......@@ -135,6 +137,9 @@ class APP_LIST_MODEL_EXPORT AppListItem {
// A shortened name for the item, used for display.
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_;
DISALLOW_COPY_AND_ASSIGN(AppListItem);
......
......@@ -21,7 +21,7 @@ class APP_LIST_MODEL_EXPORT AppListItemObserver {
virtual void ItemNameChanged() {}
// 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.
virtual void ItemBeingDestroyed() {}
......
......@@ -363,7 +363,7 @@ AppListItemView::AppListItemView(AppsGridView* apps_grid_view,
std::make_unique<AppNotificationIndicatorView>(kDefaultIndicatorColor));
notification_indicator_->SetPaintToLayer();
notification_indicator_->layer()->SetFillsBoundsOpaquely(false);
notification_indicator_->SetVisible(false);
notification_indicator_->SetVisible(item->has_notification_badge());
}
title_ = AddChildView(std::move(title));
......@@ -1117,9 +1117,9 @@ void AppListItemView::ItemNameChanged() {
base::UTF8ToUTF16(item_weak_->name()));
}
void AppListItemView::ItemBadgeVisibilityChanged(bool is_badge_visible) {
void AppListItemView::ItemBadgeVisibilityChanged() {
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() {
......
......@@ -228,7 +228,7 @@ class APP_LIST_EXPORT AppListItemView : public views::Button,
// AppListItemObserver overrides:
void ItemIconChanged(AppListConfigType config_type) override;
void ItemNameChanged() override;
void ItemBadgeVisibilityChanged(bool is_badge_visible) override;
void ItemBadgeVisibilityChanged() override;
void ItemBeingDestroyed() override;
// ui::ImplicitAnimationObserver:
......
......@@ -583,6 +583,11 @@ const char kDarkModeEnabled[] = "cros.system.dark_mode_enabled";
// background color will be calculated based on extracted wallpaper color.
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
// into this file should not be renamed, since they may be synced.
......
......@@ -210,6 +210,8 @@ ASH_PUBLIC_EXPORT extern const char kMultipasteNudges[];
ASH_PUBLIC_EXPORT extern const char kDarkModeEnabled[];
ASH_PUBLIC_EXPORT extern const char kColorModeThemed[];
ASH_PUBLIC_EXPORT extern const char kAppNotificationBadgingEnabled[];
} // namespace prefs
} // namespace ash
......
......@@ -151,24 +151,27 @@ void ShelfController::OnActiveUserPrefServiceChanged(
base::BindRepeating(&SetShelfBehaviorsFromPrefs));
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
// notification updates.
AccountId account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
cache_ =
apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id);
Observe(cache_);
if (cache_) {
// 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.
cache_->ForEachApp([this](const apps::AppUpdate& update) {
bool has_badge = update.HasBadge() == apps::mojom::OptionalBool::kTrue;
model_.UpdateItemNotification(update.AppId(), has_badge);
});
}
// Resetting the recorded pref forces the next call to UpdateAppBadging()
// 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.
UpdateAppBadging();
}
}
......@@ -218,7 +221,8 @@ void ShelfController::OnDisplayConfigurationChanged() {
}
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;
model_.UpdateItemNotification(update.AppId(), has_badge);
}
......@@ -230,7 +234,8 @@ void ShelfController::OnAppRegistryCacheWillBeDestroyed(
}
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;
auto app_id = model_.items()[index].id.app_id;
......@@ -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
......@@ -60,12 +60,18 @@ class ASH_EXPORT ShelfController : public SessionObserver,
// ShelfModelObserver:
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.
ShelfModel model_;
// Whether notification indicators are enabled for app icons in the shelf.
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.
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
......
......@@ -42,6 +42,9 @@ void MessageCenterController::RegisterProfilePrefs(
prefs::kMessageCenterLockScreenMode,
prefs::kMessageCenterLockScreenModeHide,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
registry->RegisterBooleanPref(
prefs::kAppNotificationBadgingEnabled, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
}
namespace {
......
......@@ -10,9 +10,11 @@
#include <string>
#include <utility>
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/public/cpp/notifier_metadata.h"
#include "ash/public/cpp/notifier_settings_controller.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
......@@ -26,6 +28,7 @@
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "components/prefs/pref_service.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_enums.mojom.h"
......@@ -466,6 +469,15 @@ NotifierSettingsView::NotifierSettingsView() {
TrayPopupUtils::CreateToggleButton(
this, IDS_ASH_MESSAGE_CENTER_APP_BADGING_BUTTON_TOOLTIP));
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(
std::move(app_badging_icon), std::move(app_badging_label),
std::move(app_badging_toggle));
......@@ -659,8 +671,13 @@ bool NotifierSettingsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
void NotifierSettingsView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == app_badging_toggle_) {
// TODO(tengs): Call the appropriate controller to toggle app badging once
// it is available.
SessionControllerImpl* session_controller =
Shell::Get()->session_controller();
PrefService* prefs = session_controller->GetLastActiveUserPrefService();
if (prefs) {
prefs->SetBoolean(prefs::kAppNotificationBadgingEnabled,
app_badging_toggle_->GetIsOn());
}
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