0

focus-mode: Add OAuth consent and free trials view for YTM

This CL will add an OAuth consent view and a 3 months free trials view
for the YouTube Music sound section view.

Bug: b/359225463, b/362610166
Test: Manual
Change-Id: I7dc2bf3d331b217a882d12b3cdb660b2d41a691b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5846430
Reviewed-by: Richard Chui <richui@chromium.org>
Reviewed-by: Rushan Suleymanov <rushans@google.com>
Commit-Queue: Hongyu Long <hongyulong@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1355976}
This commit is contained in:
Hongyu Long
2024-09-16 17:30:30 +00:00
committed by Chromium LUCI CQ
parent 73e6709a0b
commit 0020d95e37
23 changed files with 246 additions and 68 deletions

@ -817,11 +817,23 @@ Style notes:
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_MEDIA_CONTROLS_SOURCE_TITLE" desc="The source title shown in the media controls if a focus mode playlist is selected and playing.">
<ph name="PLAYLIST_TYPE">$1<ex>Focus sounds</ex></ph> ᐧ <ph name="PLAYLIST_TITLE">$2<ex>Nature</ex></ph>
</message>
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_OAUTH_CONSENT_LABEL" desc="The text on the label used for showing a text to mention the user the focus panel will access the YouTube Music for personalized music.">
For personalized focus playlists, allow access to YouTube Music
</message>
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_OAUTH_CONSENT_BUTTON" desc="The text on the get started button.">
Get started
</message>
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_FREE_TRIAL_LABEL" desc="The text on the label used for showing a text to mention the user to get three months free trial of YouTube Music premium.">
Stay on track with personalized focus playlists. Get YouTube Music and YouTube, ad-free, with 3 months of YouTube Premium at no cost.
</message>
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_FREE_TRIAL_BUTTON" desc="The text on the free trial button.">
Get perk
</message>
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_NON_PREMIUM_LABEL" desc="The text on the label used for showing a text to mention the user without a premium account for YouTube Music.">
For personalized playlists and more focus music, try YouTube Music Premium
To listen to music ad-free and enjoy personalized focus music, try YouTube Music Premium
</message>
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_LEARN_MORE_BUTTON" desc="The text on the learn more button.">
Learn more
Get Music Premium
</message>
<message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_OFFLINE_LABEL_ONE" desc="The text shown to the user in the first line of the sounds view when they are offline.">
You're offline.

@ -0,0 +1 @@
4867c4d599a4434f40507b63369b5a52b46cc4f8

@ -0,0 +1 @@
76dec517aa261da6643a4d1f3692291b4ad08c5d

@ -1 +1 @@
f3c0aa0fefb84d77795f5b28c635b84afde6e1a3
6e0a382db28731d280e7dd613bce630c7668b9c3

@ -1 +1 @@
011ac826b4ff366e81ebfd8aa8384288d9dc1c04
4d3f8c4653e723d52c18df19d5a6d667f26d3482

@ -0,0 +1 @@
2602d2139da529e1cbd0e96c51fb3b47f00c2769

@ -0,0 +1 @@
f25ac9233056f22745796375a4f354ab97f73768

@ -2259,6 +2259,14 @@ inline constexpr char kFocusModeDeviceId[] = "ash.focus_mode.device_id";
// An string enum pref containing the enabled sound types.
inline constexpr char kFocusModeSoundsEnabled[] =
"ash.focus_mode.sounds_enabled";
// A boolean pref of whether the focus panel shows the OAuth consent screen for
// YouTube Music.
inline constexpr char kFocusModeYTMDisplayOAuthConsent[] =
"ash.focus_mode.youtube_music.oauth";
// A boolean pref of whether the focus panel shows the view to let the user know
// a 3 months free trial for YouTube Music.
inline constexpr char kFocusModeYTMDisplayFreeTrial[] =
"ash.focus_mode.youtube_music.free_trial";
// An integer pref that holds enum value of current demo mode configuration.
// Values are defined by DemoSession::DemoModeConfig enum.

@ -222,6 +222,7 @@ class ASH_PUBLIC_EXPORT SystemTrayClient {
// Shows a page about premium plans.
virtual void ShowYouTubeMusicPremiumPage() = 0;
virtual void ShowChromebookPerksYouTubePage() = 0;
// Shows settings related to keyboards.
virtual void ShowKeyboardSettings() = 0;

@ -210,6 +210,10 @@ void TestSystemTrayClient::ShowYouTubeMusicPremiumPage() {
++show_youtube_music_premium_page_count_;
}
void TestSystemTrayClient::ShowChromebookPerksYouTubePage() {
++show_chromebook_perks_youtube_page_count_;
}
void TestSystemTrayClient::ShowKeyboardSettings() {
++show_keyboard_settings_count_;
}

@ -86,6 +86,7 @@ class ASH_PUBLIC_EXPORT TestSystemTrayClient : public SystemTrayClient {
void ShowTouchpadSettings() override;
void ShowRemapKeysSubpage(int device_id) override;
void ShowYouTubeMusicPremiumPage() override;
void ShowChromebookPerksYouTubePage() override;
void ShowKeyboardSettings() override;
void ShowPointingStickSettings() override;
void ShowNearbyShareSettings() override;
@ -228,6 +229,10 @@ class ASH_PUBLIC_EXPORT TestSystemTrayClient : public SystemTrayClient {
return show_youtube_music_premium_page_count_;
}
int show_chromebook_perks_youtube_page_count() const {
return show_chromebook_perks_youtube_page_count_;
}
int show_keyboard_settings_count() const {
return show_keyboard_settings_count_;
}
@ -281,6 +286,7 @@ class ASH_PUBLIC_EXPORT TestSystemTrayClient : public SystemTrayClient {
int show_touchpad_settings_count_ = 0;
int show_remap_keys_subpage_count_ = 0;
int show_youtube_music_premium_page_count_ = 0;
int show_chromebook_perks_youtube_page_count_ = 0;
int show_keyboard_settings_count_ = 0;
int show_pointing_stick_settings_count_ = 0;
int show_nearby_share_settings_count_ = 0;

@ -201,6 +201,14 @@ void FocusModeController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
prefs::kFocusModeSoundSection,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
// Prefs for YouTube Music.
registry->RegisterBooleanPref(
prefs::kFocusModeYTMDisplayOAuthConsent, /*default_value=*/true,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
registry->RegisterBooleanPref(
prefs::kFocusModeYTMDisplayFreeTrial, /*default_value=*/true,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
// Pref is device-local and should never be synced.
registry->RegisterStringPref(prefs::kFocusModeDeviceId, "");

@ -607,6 +607,52 @@ void FocusModeSoundsController::ReportYouTubeMusicPlayback(
youtube_music_delegate_->ReportPlayback(playback_data);
}
bool FocusModeSoundsController::ShouldDisplayYouTubeMusicOAuth() const {
if (PrefService* active_user_prefs =
Shell::Get()->session_controller()->GetActivePrefService()) {
return active_user_prefs->GetBoolean(
prefs::kFocusModeYTMDisplayOAuthConsent);
}
CHECK_IS_TEST();
return true;
}
void FocusModeSoundsController::SavePrefForDisplayYouTubeMusicOAuth() {
if (PrefService* active_user_prefs =
Shell::Get()->session_controller()->GetActivePrefService()) {
active_user_prefs->SetBoolean(prefs::kFocusModeYTMDisplayOAuthConsent,
false);
}
}
bool FocusModeSoundsController::ShouldDisplayYouTubeMusicFreeTrial() const {
if (PrefService* active_user_prefs =
Shell::Get()->session_controller()->GetActivePrefService()) {
return active_user_prefs->GetBoolean(prefs::kFocusModeYTMDisplayFreeTrial);
}
CHECK_IS_TEST();
return true;
}
void FocusModeSoundsController::SavePrefForDisplayYouTubeMusicFreeTrial() {
if (PrefService* active_user_prefs =
Shell::Get()->session_controller()->GetActivePrefService()) {
active_user_prefs->SetBoolean(prefs::kFocusModeYTMDisplayFreeTrial, false);
}
}
bool FocusModeSoundsController::IsMinorUser() {
// `ChromeFocusModeDelegate::IsMinorUser` doesn't work in browsertest, since
// it always returns true. `can_use_manta_service()` is
// `signin::Tribool::kUnknown`.
if (is_minor_user_for_testing_.has_value()) {
CHECK_IS_TEST();
return is_minor_user_for_testing_.value();
}
return FocusModeController::Get()->delegate()->IsMinorUser();
}
void FocusModeSoundsController::SetIsMinorUserForTesting(bool is_minor_user) {
CHECK_IS_TEST();
is_minor_user_for_testing_ = is_minor_user;
@ -712,17 +758,12 @@ void FocusModeSoundsController::OnPrefChanged() {
Shell::Get()->session_controller()->GetActivePrefService();
enabled_sound_sections_ = ReadSoundSectionPolicy(active_user_prefs);
// `ChromeFocusModeDelegate::IsMinorUser` doesn't work in browsertest, since
// it always returns true. `can_use_manta_service()` is
// `signin::Tribool::kUnknown`.
const bool is_minor_user =
is_minor_user_for_testing_.has_value()
? is_minor_user_for_testing_.value()
: FocusModeController::Get()->delegate()->IsMinorUser();
// TODO: If we want to block the whole YTM section, we should make changes
// here. And remove the calls to `FocusModeSoundsController::IsMinorUser()` in
// `FocusModeSoundsView`.
// Hide the YTM sound section if the flag isn't enabled or if the user is
// considered a minor user.
if (!features::IsFocusModeYTMEnabled() || is_minor_user) {
// Hide the YTM sound section if the flag isn't enabled.
if (!features::IsFocusModeYTMEnabled()) {
enabled_sound_sections_.erase(focus_mode_util::SoundType::kYouTubeMusic);
}
}

@ -162,6 +162,11 @@ class ASH_EXPORT FocusModeSoundsController
void ReportYouTubeMusicPlayback(
const youtube_music::PlaybackData& playback_data);
bool ShouldDisplayYouTubeMusicOAuth() const;
void SavePrefForDisplayYouTubeMusicOAuth();
bool ShouldDisplayYouTubeMusicFreeTrial() const;
void SavePrefForDisplayYouTubeMusicFreeTrial();
void set_soundscape_playlists_for_testing(
std::vector<std::unique_ptr<Playlist>> soundscape_playlists) {
soundscape_playlists_.swap(soundscape_playlists);
@ -182,6 +187,7 @@ class ASH_EXPORT FocusModeSoundsController
simulate_playback_for_testing_ = true;
}
bool IsMinorUser();
void SetIsMinorUserForTesting(bool is_minor_user);
private:

@ -8,6 +8,7 @@
#include "ash/public/cpp/system_tray_client.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/error_message_toast.h"
@ -19,6 +20,7 @@
#include "ash/system/focus_mode/focus_mode_controller.h"
#include "ash/system/focus_mode/focus_mode_detailed_view.h"
#include "ash/system/focus_mode/focus_mode_util.h"
#include "ash/system/focus_mode/sounds/focus_mode_sounds_controller.h"
#include "ash/system/focus_mode/sounds/playlist_view.h"
#include "ash/system/focus_mode/sounds/sound_section_view.h"
#include "ash/system/model/system_tray_model.h"
@ -31,6 +33,7 @@
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/view.h"
#include "ui/views/view_class_properties.h"
namespace ash {
@ -57,16 +60,27 @@ constexpr gfx::Insets kErrorMessageButtonInsets =
gfx::Insets::TLBR(8, 10, 8, 16);
constexpr gfx::Insets kErrorMessageLabelInsets = gfx::Insets::TLBR(8, 16, 8, 0);
std::unique_ptr<views::BoxLayoutView> CreateNonPremiumView() {
// "01 Jan 2026 00:00 UTC" in milliseconds calculated by
// https://currentmillis.com/
constexpr base::Time kFreeTrialExpryTime =
base::Time::FromMillisecondsSinceUnixEpoch(1767225600000L);
bool IsFreeTrialExpired(base::Time now) {
return now >= kFreeTrialExpryTime;
}
std::unique_ptr<views::BoxLayoutView> CreateYouTubeMusicAlternateViewBase(
const int label_message_id,
const int button_message_id,
views::Button::PressedCallback callback) {
auto box_view = std::make_unique<views::BoxLayoutView>();
box_view->SetOrientation(views::BoxLayout::Orientation::kVertical);
box_view->SetCrossAxisAlignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
box_view->SetBetweenChildSpacing(kNonPremiumChildViewsSpacing);
auto* label = box_view->AddChildView(
std::make_unique<views::Label>(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_NON_PREMIUM_LABEL)));
auto* label = box_view->AddChildView(std::make_unique<views::Label>(
l10n_util::GetStringUTF16(label_message_id)));
label->SetMultiLine(true);
// For the label view with multiple lines, we need to set the max width for
// it to calculate the total height of multiple lines.
@ -77,20 +91,49 @@ std::unique_ptr<views::BoxLayoutView> CreateNonPremiumView() {
label->SetEnabledColorId(cros_tokens::kCrosSysOnSurface);
auto* button = box_view->AddChildView(std::make_unique<PillButton>(
views::Button::PressedCallback(base::BindRepeating([]() {
Shell::Get()
->system_tray_model()
->client()
->ShowYouTubeMusicPremiumPage();
})),
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_LEARN_MORE_BUTTON),
std::move(callback), l10n_util::GetStringUTF16(button_message_id),
PillButton::Type::kSecondaryWithoutIcon));
button->SetBackgroundColorId(cros_tokens::kCrosSysHighlightShape);
button->SetButtonTextColorId(cros_tokens::kCrosSysSystemOnPrimaryContainer);
return box_view;
}
std::unique_ptr<views::BoxLayoutView> CreateFreeTrialView() {
return CreateYouTubeMusicAlternateViewBase(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_FREE_TRIAL_LABEL,
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_FREE_TRIAL_BUTTON,
base::BindRepeating([]() {
FocusModeController::Get()
->focus_mode_sounds_controller()
->SavePrefForDisplayYouTubeMusicFreeTrial();
Shell::Get()
->system_tray_model()
->client()
->ShowChromebookPerksYouTubePage();
}));
}
std::unique_ptr<views::BoxLayoutView> CreateNonPremiumView() {
return CreateYouTubeMusicAlternateViewBase(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_NON_PREMIUM_LABEL,
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_LEARN_MORE_BUTTON,
base::BindRepeating([]() {
Shell::Get()
->system_tray_model()
->client()
->ShowYouTubeMusicPremiumPage();
}));
}
std::unique_ptr<views::BoxLayoutView> CreateOAuthView(
views::Button::PressedCallback callback) {
return CreateYouTubeMusicAlternateViewBase(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_OAUTH_CONSENT_LABEL,
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_OAUTH_CONSENT_BUTTON,
std::move(callback));
}
std::unique_ptr<views::Label> CreateOfflineLabel(const int message_id) {
auto label =
std::make_unique<views::Label>(l10n_util::GetStringUTF16(message_id));
@ -153,21 +196,6 @@ FocusModeSoundsView::FocusModeSoundsView(
if (is_network_connected) {
CreatesSoundSectionViews(sound_sections);
if (soundscape_container_) {
// Start downloading playlists for Soundscape.
DownloadPlaylistsForType(/*is_soundscape_type=*/true);
}
if (youtube_music_container_) {
// Set the no premium callback and start downloading playlists for YouTube
// Music.
sounds_controller->SetYouTubeMusicNoPremiumCallback(base::BindRepeating(
&FocusModeSoundsView::ToggleYouTubeMusicAlternateView,
weak_factory_.GetWeakPtr(), /*show=*/true));
DownloadPlaylistsForType(/*is_soundscape_type=*/false);
}
if (should_show_soundscapes) {
OnSoundscapeButtonToggled();
} else {
@ -354,17 +382,56 @@ void FocusModeSoundsView::CreatesSoundSectionViews(
if (base::Contains(sound_sections, focus_mode_util::SoundType::kSoundscape)) {
soundscape_container_ = AddChildView(std::make_unique<SoundSectionView>(
focus_mode_util::SoundType::kSoundscape));
// Start downloading playlists for Soundscape.
DownloadPlaylistsForType(/*is_soundscape_type=*/true);
}
if (base::Contains(sound_sections,
focus_mode_util::SoundType::kYouTubeMusic)) {
youtube_music_container_ = AddChildView(std::make_unique<SoundSectionView>(
focus_mode_util::SoundType::kYouTubeMusic));
youtube_music_container_->SetAlternateView(CreateNonPremiumView());
auto* sounds_controller =
FocusModeController::Get()->focus_mode_sounds_controller();
if (sounds_controller->ShouldDisplayYouTubeMusicOAuth()) {
youtube_music_container_->SetAlternateView(
CreateOAuthView(base::BindRepeating(
&FocusModeSoundsView::OnOAuthGetStartedButtonPressed,
weak_factory_.GetWeakPtr())));
ToggleYouTubeMusicAlternateView(/*show=*/true);
return;
}
if (!sounds_controller->IsMinorUser() &&
sounds_controller->ShouldDisplayYouTubeMusicFreeTrial() &&
!IsFreeTrialExpired(base::Time::Now())) {
youtube_music_container_->SetAlternateView(CreateFreeTrialView());
} else {
youtube_music_container_->SetAlternateView(CreateNonPremiumView());
}
ToggleYouTubeMusicAlternateView(/*show=*/false);
DownloadPlaylistsForType(/*is_soundscape_type=*/false);
}
}
void FocusModeSoundsView::OnOAuthGetStartedButtonPressed() {
auto* sounds_controller =
FocusModeController::Get()->focus_mode_sounds_controller();
sounds_controller->SavePrefForDisplayYouTubeMusicOAuth();
// Sets the alternate view to either the free trial view or the non-premium
// view for `youtube_music_container_`.
if (!sounds_controller->IsMinorUser() &&
sounds_controller->ShouldDisplayYouTubeMusicFreeTrial() &&
!IsFreeTrialExpired(base::Time::Now())) {
youtube_music_container_->SetAlternateView(CreateFreeTrialView());
} else {
youtube_music_container_->SetAlternateView(CreateNonPremiumView());
}
ToggleYouTubeMusicAlternateView(/*show=*/false);
DownloadPlaylistsForType(/*is_soundscape_type=*/false);
}
void FocusModeSoundsView::ToggleYouTubeMusicAlternateView(bool show) {
CHECK(youtube_music_container_);
youtube_music_container_->ShowAlternateView(show);
@ -395,12 +462,19 @@ void FocusModeSoundsView::MayShowSoundscapeContainer(bool show) {
}
void FocusModeSoundsView::DownloadPlaylistsForType(bool is_soundscape_type) {
FocusModeController::Get()
->focus_mode_sounds_controller()
->DownloadPlaylistsForType(
is_soundscape_type,
base::BindOnce(&FocusModeSoundsView::UpdateSoundsView,
weak_factory_.GetWeakPtr()));
auto* sounds_controller =
FocusModeController::Get()->focus_mode_sounds_controller();
// Set the no premium callback only if we start downloading the YTM playlists.
if (!is_soundscape_type) {
sounds_controller->SetYouTubeMusicNoPremiumCallback(base::BindRepeating(
&FocusModeSoundsView::ToggleYouTubeMusicAlternateView,
weak_factory_.GetWeakPtr(), /*show=*/true));
}
sounds_controller->DownloadPlaylistsForType(
is_soundscape_type, base::BindOnce(&FocusModeSoundsView::UpdateSoundsView,
weak_factory_.GetWeakPtr()));
}
void FocusModeSoundsView::MaybeDismissErrorMessage() {

@ -66,10 +66,15 @@ class ASH_EXPORT FocusModeSoundsView
void CreateHeader(const base::flat_set<focus_mode_util::SoundType>& sections,
bool is_network_connected);
// Creates `soundscape_container_` and `youtube_music_container_`.
// Creates `soundscape_container_` and `youtube_music_container_` and may
// download playlists.
void CreatesSoundSectionViews(
const base::flat_set<focus_mode_util::SoundType>& sections);
// Called when the Get started button in the YouTube Music OAuth consent view
// was pressed.
void OnOAuthGetStartedButtonPressed();
// Toggles YouTube Music alternate view. It's used to update the UIs for
// non-premium account.
void ToggleYouTubeMusicAlternateView(bool show);

@ -74,6 +74,10 @@ void SoundSectionView::ShowAlternateView(bool show_alternate_view) {
void SoundSectionView::SetAlternateView(
std::unique_ptr<views::BoxLayoutView> alternate_view) {
CHECK(alternate_view);
if (alternate_view_.get()) {
RemoveChildViewT(std::exchange(alternate_view_, nullptr));
}
alternate_view_ = AddChildView(std::move(alternate_view));
}

@ -361,6 +361,8 @@ enum {
kAccessibilityFlashNotificationsColor = 100299,
kPinnedChromeLabsMigrationComplete = 100300,
kAccessibilityFaceGazeGesturesToKeyCombos = 100301,
kFocusModeYTMDisplayOAuthConsent = 100302,
kFocusModeYTMDisplayFreeTrial = 100303,
// See components/sync_preferences/README.md about adding new entries here.
// vvvvv IMPORTANT! vvvvv
// Note to the reviewer: IT IS YOUR RESPONSIBILITY to ensure that new syncable
@ -750,6 +752,14 @@ constexpr auto kChromeSyncablePrefsAllowlist = base::MakeFixedFlatMap<
{syncable_prefs_ids::kFocusModeSoundSection, syncer::OS_PREFERENCES,
sync_preferences::PrefSensitivity::kNone,
sync_preferences::MergeBehavior::kNone}},
{ash::prefs::kFocusModeYTMDisplayOAuthConsent,
{syncable_prefs_ids::kFocusModeYTMDisplayOAuthConsent,
syncer::OS_PREFERENCES, sync_preferences::PrefSensitivity::kNone,
sync_preferences::MergeBehavior::kNone}},
{ash::prefs::kFocusModeYTMDisplayFreeTrial,
{syncable_prefs_ids::kFocusModeYTMDisplayFreeTrial, syncer::OS_PREFERENCES,
sync_preferences::PrefSensitivity::kNone,
sync_preferences::MergeBehavior::kNone}},
{ash::prefs::kKeyboardDefaultChromeOSSettings,
{syncable_prefs_ids::kKeyboardDefaultChromeOSSettings,
syncer::OS_PREFERENCES, sync_preferences::PrefSensitivity::kNone,

@ -94,25 +94,6 @@ IN_PROC_BROWSER_TEST_F(FocusModePolicyTest, FocusModeSounds_Enabled) {
testing::Pair(testing::NotNull(), testing::NotNull()));
}
// Tests that even though we enabled both Sounscape type and YouTube Music type
// of playlists; however, if the user is a minor user, YouTube Music will be
// unavailable.
IN_PROC_BROWSER_TEST_F(FocusModePolicyTest,
FocusModeSounds_Enabled_ForMinorUser) {
FocusModeController::Get()
->focus_mode_sounds_controller()
->SetIsMinorUserForTesting(true);
SetPolicyValue("enabled");
auto* quick_settings = OpenQuickSettings();
ClickOnFocusTile(quick_settings);
FocusModeSoundsView* sounds_view = GetSoundsView(quick_settings);
EXPECT_THAT(sounds_view->GetVisible(), testing::Eq(true));
EXPECT_THAT(sounds_view->soundscape_views(),
testing::Pair(testing::IsNull(), testing::NotNull()));
EXPECT_THAT(sounds_view->youtube_music_views(),
testing::Pair(testing::IsNull(), testing::IsNull()));
}
IN_PROC_BROWSER_TEST_F(FocusModePolicyTest, FocusModeSounds_FocusSoundsOnly) {
SetPolicyValue("focus-sounds");
auto* quick_settings = OpenQuickSettings();

@ -868,6 +868,7 @@ void SystemTrayClientImpl::ShowRemapKeysSubpage(int device_id) {
void SystemTrayClientImpl::ShowYouTubeMusicPremiumPage() {
DCHECK(ash::features::IsFocusModeEnabled());
DCHECK(ash::features::IsFocusModeYTMEnabled());
base::RecordAction(base::UserMetricsAction("ShowYouTubeMusicPremiumPage"));
const GURL official_url(chrome::kYoutubeMusicPremiumURL);
@ -899,6 +900,12 @@ void SystemTrayClientImpl::ShowYouTubeMusicPremiumPage() {
official_url));
}
void SystemTrayClientImpl::ShowChromebookPerksYouTubePage() {
DCHECK(ash::features::IsFocusModeEnabled());
DCHECK(ash::features::IsFocusModeYTMEnabled());
OpenInBrowser(GURL(chrome::kChromebookPerksYouTubePage));
}
void SystemTrayClientImpl::ShowEolInfoPage() {
const bool use_offer_url = ash::features::kEolIncentiveParam.Get() !=
ash::features::EolIncentiveParam::kNoOffer &&

@ -121,6 +121,7 @@ class SystemTrayClientImpl : public ash::SystemTrayClient,
void ShowTouchpadSettings() override;
void ShowRemapKeysSubpage(int device_id) override;
void ShowYouTubeMusicPremiumPage() override;
void ShowChromebookPerksYouTubePage() override;
void ShowKeyboardSettings() override;
void ShowPointingStickSettings() override;
void ShowNearbyShareSettings() override;

@ -882,6 +882,10 @@ inline constexpr char16_t kDeviceExtendedUpdatesLearnMoreURL[] =
// The URL for the YoutTube Music Premium signup page.
inline constexpr char kYoutubeMusicPremiumURL[] =
"https://music.youtube.com/music_premium";
// The URL for the Chromebook Perks page for YouTube.
inline constexpr char kChromebookPerksYouTubePage[] =
"https://www.google.com/chromebook/perks/?id=youtube.2020";
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_MAC)

@ -641,6 +641,8 @@ chromium-metrics-reviews@google.com.
<int value="100299" label="kAccessibilityFlashNotificationsColor"/>
<int value="100300" label="PinnedChromeLabsMigrationComplete"/>
<int value="100301" label="AccessibilityFaceGazeGesturesToKeyCombos"/>
<int value="100302" label="FocusModeYTMDisplayOAuthConsent"/>
<int value="100303" label="FocusModeYTMDisplayFreeTrial"/>
<!-- LINT.ThenChange(/chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc:ChromeSyncablePref)-->
<!-- LINT.IfChange(IosSyncablePref) -->