blob: 46db40191e7a91be171266dc8f181e6c604da2af [file] [log] [blame]
// Copyright 2017 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 "chrome/browser/content_settings/sound_content_setting_observer.h"
#include "build/build_config.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/profiles/profile.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/ukm/content/source_url_recorder.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/common/url_constants.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/tabs/tab_utils.h"
#endif
DEFINE_WEB_CONTENTS_USER_DATA_KEY(SoundContentSettingObserver);
SoundContentSettingObserver::SoundContentSettingObserver(
content::WebContents* contents)
: content::WebContentsObserver(contents),
logged_site_muted_ukm_(false),
observer_(this) {
host_content_settings_map_ = HostContentSettingsMapFactory::GetForProfile(
Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
observer_.Add(host_content_settings_map_);
}
SoundContentSettingObserver::~SoundContentSettingObserver() = default;
void SoundContentSettingObserver::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (navigation_handle->IsInMainFrame() && navigation_handle->HasCommitted() &&
!navigation_handle->IsSameDocument()) {
MuteOrUnmuteIfNecessary();
logged_site_muted_ukm_ = false;
}
}
void SoundContentSettingObserver::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
std::string resource_identifier) {
if (content_type == CONTENT_SETTINGS_TYPE_SOUND) {
MuteOrUnmuteIfNecessary();
CheckSoundBlocked(web_contents()->IsCurrentlyAudible());
}
}
void SoundContentSettingObserver::MuteOrUnmuteIfNecessary() {
bool mute = GetCurrentContentSetting() == CONTENT_SETTING_BLOCK;
// TabMutedReason does not exist on Android.
#if defined(OS_ANDROID)
web_contents()->SetAudioMuted(mute);
#else
// We don't want to overwrite TabMutedReason with no change.
if (mute == web_contents()->IsAudioMuted())
return;
TabMutedReason reason = chrome::GetTabAudioMutedReason(web_contents());
// Do not unmute if we're muted due to media capture.
if (!mute && reason == TabMutedReason::MEDIA_CAPTURE)
return;
// Do not unmute if we're muted due to audio indicator.
if (!mute && reason == TabMutedReason::AUDIO_INDICATOR)
return;
// Do not override the decisions of an extension.
if (reason == TabMutedReason::EXTENSION)
return;
// Don't unmute a chrome:// URL if the tab has been explicitly muted on a
// chrome:// URL.
if (reason == TabMutedReason::CONTENT_SETTING_CHROME &&
web_contents()->GetLastCommittedURL().SchemeIs(
content::kChromeUIScheme)) {
return;
}
chrome::SetTabAudioMuted(web_contents(), mute,
TabMutedReason::CONTENT_SETTING, std::string());
#endif // defined(OS_ANDROID)
}
ContentSetting SoundContentSettingObserver::GetCurrentContentSetting() {
GURL url = web_contents()->GetLastCommittedURL();
return host_content_settings_map_->GetContentSetting(
url, url, CONTENT_SETTINGS_TYPE_SOUND, std::string());
}
void SoundContentSettingObserver::OnAudioStateChanged(bool is_audible) {
CheckSoundBlocked(is_audible);
}
void SoundContentSettingObserver::CheckSoundBlocked(bool is_audible) {
if (is_audible && GetCurrentContentSetting() == CONTENT_SETTING_BLOCK) {
// The tab has tried to play sound, but was muted.
TabSpecificContentSettings* settings =
TabSpecificContentSettings::FromWebContents(web_contents());
if (settings)
settings->OnAudioBlocked();
RecordSiteMutedUKM();
}
}
void SoundContentSettingObserver::RecordSiteMutedUKM() {
// We only want to log 1 event per navigation.
if (logged_site_muted_ukm_)
return;
logged_site_muted_ukm_ = true;
ukm::builders::Media_SiteMuted(
ukm::GetSourceIdForWebContentsDocument(web_contents()))
.SetMuteReason(GetSiteMutedReason())
.Record(ukm::UkmRecorder::Get());
}
SoundContentSettingObserver::MuteReason
SoundContentSettingObserver::GetSiteMutedReason() {
const GURL url = web_contents()->GetLastCommittedURL();
content_settings::SettingInfo info;
host_content_settings_map_->GetWebsiteSetting(
url, url, CONTENT_SETTINGS_TYPE_SOUND, std::string(), &info);
DCHECK_EQ(content_settings::SETTING_SOURCE_USER, info.source);
if (info.primary_pattern == ContentSettingsPattern::Wildcard() &&
info.secondary_pattern == ContentSettingsPattern::Wildcard()) {
return MuteReason::kMuteByDefault;
}
return MuteReason::kSiteException;
}