Chromium Code Reviews| Index: chrome/browser/permissions/permission_decision_auto_blocker.cc |
| diff --git a/chrome/browser/permissions/permission_decision_auto_blocker.cc b/chrome/browser/permissions/permission_decision_auto_blocker.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a610fb8e7d9d3822558f413505a72e7832b73b91 |
| --- /dev/null |
| +++ b/chrome/browser/permissions/permission_decision_auto_blocker.cc |
| @@ -0,0 +1,171 @@ |
| +// 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 "chrome/browser/permissions/permission_decision_auto_blocker.h" |
| + |
| +#include <memory> |
| + |
| +#include "base/feature_list.h" |
| +#include "base/logging.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| +#include "chrome/browser/permissions/permission_uma_util.h" |
| +#include "chrome/browser/permissions/permission_util.h" |
| +#include "chrome/common/chrome_features.h" |
| +#include "components/content_settings/core/browser/host_content_settings_map.h" |
| +#include "components/variations/variations_associated_data.h" |
| +#include "content/public/browser/permission_type.h" |
| +#include "url/gurl.h" |
| + |
| +namespace { |
| + |
| +// The default number of times that users may explicitly dismiss a permission |
| +// prompt from an origin before it is automatically blocked. |
| +const int kPromptDismissalsBeforeBlock = 3; |
| + |
| +std::unique_ptr<base::DictionaryValue> GetOriginDict( |
| + HostContentSettingsMap* settings, |
| + const GURL& origin_url) { |
| + std::unique_ptr<base::DictionaryValue> dict = |
| + base::DictionaryValue::From(settings->GetWebsiteSetting( |
| + origin_url, origin_url, |
| + CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, std::string(), |
| + nullptr)); |
| + if (!dict) |
| + return base::WrapUnique(new base::DictionaryValue()); |
| + |
| + return dict; |
| +} |
| + |
| +base::DictionaryValue* GetOrCreatePermissionDict( |
| + base::DictionaryValue* origin_dict, |
| + const std::string& permission) { |
| + base::DictionaryValue* permission_dict = nullptr; |
| + if (!origin_dict->GetDictionaryWithoutPathExpansion(permission, |
| + &permission_dict)) { |
| + permission_dict = new base::DictionaryValue(); |
| + origin_dict->SetWithoutPathExpansion(permission, |
| + base::WrapUnique(permission_dict)); |
| + } |
| + |
| + return permission_dict; |
| +} |
| + |
| +} // namespace |
| + |
| +// static |
| +const char PermissionDecisionAutoBlocker::kPromptDismissCountKey[] = |
| + "dismiss_count"; |
| + |
| +// static |
| +const char PermissionDecisionAutoBlocker::kPromptIgnoreCountKey[] = |
| + "ignore_count"; |
| + |
| +// static |
| +void PermissionDecisionAutoBlocker::RemoveCountsByUrl( |
| + Profile* profile, |
| + base::Callback<bool(const GURL& url)> filter) { |
| + HostContentSettingsMap* map = |
| + HostContentSettingsMapFactory::GetForProfile(profile); |
| + |
| + std::unique_ptr<ContentSettingsForOneType> settings( |
| + new ContentSettingsForOneType); |
| + map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, |
| + std::string(), settings.get()); |
| + |
| + for (const auto& site : *settings) { |
| + GURL origin(site.primary_pattern.ToString()); |
| + |
| + if (origin.is_valid() && filter.Run(origin)) { |
| + map->SetWebsiteSettingDefaultScope( |
| + origin, GURL(), CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, |
| + std::string(), nullptr); |
| + } |
| + } |
| +} |
| + |
| +PermissionDecisionAutoBlocker::PermissionDecisionAutoBlocker(Profile* profile) |
| + : profile_(profile), |
| + prompt_dismissals_before_block_(kPromptDismissalsBeforeBlock) { |
| + UpdateFromVariations(); |
| +} |
| + |
| +int PermissionDecisionAutoBlocker::RecordIgnore( |
| + const GURL& url, |
| + content::PermissionType permission) { |
| + int current_ignore_count = |
| + RecordAction(url, permission, kPromptIgnoreCountKey); |
|
kcarattini
2016/08/08 06:14:31
Can you rename RecordAction to make it more clear
dominickn
2016/08/08 06:26:08
Done.
|
| + |
| + // |current_ignore_count| is always (count before this ignore + 1) |
|
kcarattini
2016/08/08 06:14:31
I find it confusing that this and the previous Rec
dominickn
2016/08/08 06:26:08
Done.
|
| + PermissionUmaUtil::PermissionPromptIgnoreCount(permission, |
| + current_ignore_count - 1); |
| + |
| + return current_ignore_count; |
| +} |
| + |
| +bool PermissionDecisionAutoBlocker::ShouldChangeDismissalToBlock( |
| + const GURL& url, |
| + content::PermissionType permission) { |
| + int current_dismissal_count = |
| + RecordAction(url, permission, kPromptDismissCountKey); |
| + |
| + // |current_dismissal_count| is always (count before this dismissal + 1) |
| + PermissionUmaUtil::PermissionPromptDismissCount(permission, |
| + current_dismissal_count - 1); |
| + |
| + if (!base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften)) |
| + return false; |
| + |
| + return current_dismissal_count >= prompt_dismissals_before_block_; |
| +} |
| + |
| +int PermissionDecisionAutoBlocker::GetActionCountForTest( |
| + const GURL& url, |
| + content::PermissionType permission, |
| + const char* key) { |
| + HostContentSettingsMap* map = |
| + HostContentSettingsMapFactory::GetForProfile(profile_); |
| + std::unique_ptr<base::DictionaryValue> dict = GetOriginDict(map, url); |
| + |
| + base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( |
| + dict.get(), PermissionUtil::GetPermissionString(permission)); |
| + |
| + int current_count = 0; |
| + permission_dict->GetInteger(key, ¤t_count); |
| + return current_count; |
| +} |
| + |
| +int PermissionDecisionAutoBlocker::RecordAction( |
| + const GURL& url, |
| + content::PermissionType permission, |
| + const char* key) { |
| + HostContentSettingsMap* map = |
| + HostContentSettingsMapFactory::GetForProfile(profile_); |
| + std::unique_ptr<base::DictionaryValue> dict = GetOriginDict(map, url); |
| + |
| + base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( |
| + dict.get(), PermissionUtil::GetPermissionString(permission)); |
| + |
| + int current_count = 0; |
| + permission_dict->GetInteger(key, ¤t_count); |
| + permission_dict->SetInteger(key, ++current_count); |
| + |
| + map->SetWebsiteSettingDefaultScope( |
| + url, GURL(), CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, |
| + std::string(), std::move(dict)); |
| + |
| + return current_count; |
| +} |
| + |
| +void PermissionDecisionAutoBlocker::UpdateFromVariations() { |
| + int prompt_dismissals = -1; |
| + std::string value = variations::GetVariationParamValueByFeature( |
| + features::kBlockPromptsIfDismissedOften, kPromptDismissCountKey); |
| + |
| + // If converting the value fails, stick with the default value. |
| + if (base::StringToInt(value, &prompt_dismissals) && prompt_dismissals > 0) |
| + prompt_dismissals_before_block_ = prompt_dismissals; |
| +} |