blob: 422f18b73152d1f55f0666225e047c25cc057172 [file] [log] [blame]
// Copyright 2014 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 "components/permissions/permission_uma_util.h"
#include <utility>
#include "base/command_line.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/permissions/permission_decision_auto_blocker.h"
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_util.h"
#include "components/permissions/permissions_client.h"
#include "components/ukm/content/source_url_recorder.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/web_contents.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/blink/public/common/loader/network_utils.h"
#include "url/gurl.h"
#if defined(OS_ANDROID)
#include "base/android/jni_string.h"
#include "components/permissions/android/jni_headers/PermissionUmaUtil_jni.h"
#endif
namespace permissions {
#define PERMISSION_BUBBLE_TYPE_UMA(metric_name, permission_bubble_type) \
base::UmaHistogramEnumeration(metric_name, permission_bubble_type, \
PermissionRequestType::NUM)
#define PERMISSION_BUBBLE_GESTURE_TYPE_UMA( \
gesture_metric_name, no_gesture_metric_name, gesture_type, \
permission_bubble_type) \
if (gesture_type == PermissionRequestGestureType::GESTURE) { \
PERMISSION_BUBBLE_TYPE_UMA(gesture_metric_name, permission_bubble_type); \
} else if (gesture_type == PermissionRequestGestureType::NO_GESTURE) { \
PERMISSION_BUBBLE_TYPE_UMA(no_gesture_metric_name, \
permission_bubble_type); \
}
using content::PermissionType;
namespace {
const int kPriorCountCap = 10;
std::string GetPermissionRequestString(PermissionRequestType type) {
switch (type) {
case PermissionRequestType::MULTIPLE:
return "AudioAndVideoCapture";
case PermissionRequestType::QUOTA:
return "Quota";
case PermissionRequestType::DOWNLOAD:
return "MultipleDownload";
case PermissionRequestType::REGISTER_PROTOCOL_HANDLER:
return "RegisterProtocolHandler";
case PermissionRequestType::PERMISSION_GEOLOCATION:
return "Geolocation";
case PermissionRequestType::PERMISSION_MIDI_SYSEX:
return "MidiSysEx";
case PermissionRequestType::PERMISSION_NOTIFICATIONS:
return "Notifications";
case PermissionRequestType::PERMISSION_PROTECTED_MEDIA_IDENTIFIER:
return "ProtectedMedia";
case PermissionRequestType::PERMISSION_FLASH:
return "Flash";
case PermissionRequestType::PERMISSION_MEDIASTREAM_MIC:
return "AudioCapture";
case PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA:
return "VideoCapture";
case PermissionRequestType::PERMISSION_SECURITY_KEY_ATTESTATION:
return "SecurityKeyAttestation";
case PermissionRequestType::PERMISSION_PAYMENT_HANDLER:
return "PaymentHandler";
case PermissionRequestType::PERMISSION_NFC:
return "Nfc";
case PermissionRequestType::PERMISSION_CLIPBOARD_READ_WRITE:
return "ClipboardReadWrite";
case PermissionRequestType::PERMISSION_VR:
return "VR";
case PermissionRequestType::PERMISSION_AR:
return "AR";
case PermissionRequestType::PERMISSION_STORAGE_ACCESS:
return "StorageAccess";
case PermissionRequestType::PERMISSION_CAMERA_PAN_TILT_ZOOM:
return "CameraPanTiltZoom";
case PermissionRequestType::PERMISSION_WINDOW_PLACEMENT:
return "WindowPlacement";
case PermissionRequestType::PERMISSION_FONT_ACCESS:
return "FontAccess";
case PermissionRequestType::PERMISSION_IDLE_DETECTION:
return "IdleDetection";
default:
NOTREACHED();
return "";
}
}
void RecordEngagementMetric(const std::vector<PermissionRequest*>& requests,
content::WebContents* web_contents,
const std::string& action) {
PermissionRequestType type = requests[0]->GetPermissionRequestType();
if (requests.size() > 1)
type = PermissionRequestType::MULTIPLE;
DCHECK(action == "Accepted" || action == "Denied" || action == "Dismissed" ||
action == "Ignored");
std::string name = "Permissions.Engagement." + action + '.' +
GetPermissionRequestString(type);
double engagement_score = PermissionsClient::Get()->GetSiteEngagementScore(
web_contents->GetBrowserContext(), requests[0]->GetOrigin());
base::UmaHistogramPercentage(name, engagement_score);
}
void RecordPermissionActionUkm(
PermissionAction action,
PermissionRequestGestureType gesture_type,
ContentSettingsType permission,
int dismiss_count,
int ignore_count,
PermissionSourceUI source_ui,
PermissionPromptDisposition ui_disposition,
base::Optional<bool> has_three_consecutive_denies,
base::Optional<ukm::SourceId> source_id) {
// Only record the permission change if the origin is in the history.
if (!source_id.has_value())
return;
size_t num_values = 0;
ukm::builders::Permission builder(source_id.value());
builder.SetAction(static_cast<int64_t>(action))
.SetGesture(static_cast<int64_t>(gesture_type))
.SetPermissionType(static_cast<int64_t>(
ContentSettingTypeToHistogramValue(permission, &num_values)))
.SetPriorDismissals(std::min(kPriorCountCap, dismiss_count))
.SetPriorIgnores(std::min(kPriorCountCap, ignore_count))
.SetSource(static_cast<int64_t>(source_ui))
.SetPromptDisposition(static_cast<int64_t>(ui_disposition));
if (has_three_consecutive_denies.has_value()) {
int64_t satisfied_adaptive_triggers = 0;
if (has_three_consecutive_denies.value())
satisfied_adaptive_triggers |=
static_cast<int64_t>(AdaptiveTriggers::THREE_CONSECUTIVE_DENIES);
builder.SetSatisfiedAdaptiveTriggers(satisfied_adaptive_triggers);
}
builder.Record(ukm::UkmRecorder::Get());
}
std::string GetPromptDispositionString(
PermissionPromptDisposition ui_disposition) {
switch (ui_disposition) {
case PermissionPromptDisposition::ANCHORED_BUBBLE:
return "AnchoredBubble";
case PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP:
return "LocationBarLeftChip";
case PermissionPromptDisposition::LOCATION_BAR_RIGHT_ANIMATED_ICON:
return "LocationBarRightAnimatedIcon";
case PermissionPromptDisposition::LOCATION_BAR_RIGHT_STATIC_ICON:
return "LocationBarRightStaticIcon";
case PermissionPromptDisposition::MINI_INFOBAR:
return "MiniInfobar";
case PermissionPromptDisposition::MODAL_DIALOG:
return "ModalDialog";
case PermissionPromptDisposition::NONE_VISIBLE:
return "NoneVisible";
case PermissionPromptDisposition::NOT_APPLICABLE:
return "NotApplicable";
}
NOTREACHED();
return "";
}
} // anonymous namespace
// PermissionUmaUtil ----------------------------------------------------------
const char PermissionUmaUtil::kPermissionsPromptShown[] =
"Permissions.Prompt.Shown";
const char PermissionUmaUtil::kPermissionsPromptShownGesture[] =
"Permissions.Prompt.Shown.Gesture";
const char PermissionUmaUtil::kPermissionsPromptShownNoGesture[] =
"Permissions.Prompt.Shown.NoGesture";
const char PermissionUmaUtil::kPermissionsPromptAccepted[] =
"Permissions.Prompt.Accepted";
const char PermissionUmaUtil::kPermissionsPromptAcceptedGesture[] =
"Permissions.Prompt.Accepted.Gesture";
const char PermissionUmaUtil::kPermissionsPromptAcceptedNoGesture[] =
"Permissions.Prompt.Accepted.NoGesture";
const char PermissionUmaUtil::kPermissionsPromptDenied[] =
"Permissions.Prompt.Denied";
const char PermissionUmaUtil::kPermissionsPromptDeniedGesture[] =
"Permissions.Prompt.Denied.Gesture";
const char PermissionUmaUtil::kPermissionsPromptDeniedNoGesture[] =
"Permissions.Prompt.Denied.NoGesture";
// Make sure you update histograms.xml permission histogram_suffix if you
// add new permission
void PermissionUmaUtil::PermissionRequested(ContentSettingsType content_type,
const GURL& requesting_origin) {
PermissionType permission;
bool success = PermissionUtil::GetPermissionType(content_type, &permission);
DCHECK(success);
bool secure_origin = blink::network_utils::IsOriginSecure(requesting_origin);
base::UmaHistogramEnumeration("ContentSettings.PermissionRequested",
permission, PermissionType::NUM);
if (secure_origin) {
base::UmaHistogramEnumeration(
"ContentSettings.PermissionRequested_SecureOrigin", permission,
PermissionType::NUM);
} else {
base::UmaHistogramEnumeration(
"ContentSettings.PermissionRequested_InsecureOrigin", permission,
PermissionType::NUM);
}
}
void PermissionUmaUtil::PermissionRevoked(
ContentSettingsType permission,
PermissionSourceUI source_ui,
const GURL& revoked_origin,
content::BrowserContext* browser_context) {
// TODO(tsergeant): Expand metrics definitions for revocation to include all
// permissions.
if (permission == ContentSettingsType::NOTIFICATIONS ||
permission == ContentSettingsType::GEOLOCATION ||
permission == ContentSettingsType::MEDIASTREAM_MIC ||
permission == ContentSettingsType::MEDIASTREAM_CAMERA ||
permission == ContentSettingsType::IDLE_DETECTION) {
// An unknown gesture type is passed in since gesture type is only
// applicable in prompt UIs where revocations are not possible.
RecordPermissionAction(permission, PermissionAction::REVOKED, source_ui,
PermissionRequestGestureType::UNKNOWN,
PermissionPromptDisposition::NOT_APPLICABLE,
revoked_origin,
/*web_contents=*/nullptr, browser_context);
}
}
void PermissionUmaUtil::RecordEmbargoPromptSuppression(
PermissionEmbargoStatus embargo_status) {
base::UmaHistogramEnumeration(
"Permissions.AutoBlocker.EmbargoPromptSuppression", embargo_status,
PermissionEmbargoStatus::NUM);
}
void PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(
PermissionStatusSource source) {
// Explicitly switch to ensure that any new
// PermissionStatusSource values are dealt with appropriately.
switch (source) {
case PermissionStatusSource::MULTIPLE_DISMISSALS:
PermissionUmaUtil::RecordEmbargoPromptSuppression(
PermissionEmbargoStatus::REPEATED_DISMISSALS);
break;
case PermissionStatusSource::MULTIPLE_IGNORES:
PermissionUmaUtil::RecordEmbargoPromptSuppression(
PermissionEmbargoStatus::REPEATED_IGNORES);
break;
case PermissionStatusSource::UNSPECIFIED:
case PermissionStatusSource::KILL_SWITCH:
case PermissionStatusSource::INSECURE_ORIGIN:
case PermissionStatusSource::FEATURE_POLICY:
case PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN:
case PermissionStatusSource::PORTAL:
// The permission wasn't under embargo, so don't record anything. We may
// embargo it later.
break;
}
}
void PermissionUmaUtil::RecordEmbargoStatus(
PermissionEmbargoStatus embargo_status) {
base::UmaHistogramEnumeration("Permissions.AutoBlocker.EmbargoStatus",
embargo_status, PermissionEmbargoStatus::NUM);
}
void PermissionUmaUtil::PermissionPromptShown(
const std::vector<PermissionRequest*>& requests) {
DCHECK(!requests.empty());
PermissionRequestType request_type = PermissionRequestType::MULTIPLE;
PermissionRequestGestureType gesture_type =
PermissionRequestGestureType::UNKNOWN;
if (requests.size() == 1) {
request_type = requests[0]->GetPermissionRequestType();
gesture_type = requests[0]->GetGestureType();
}
PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptShown, request_type);
PERMISSION_BUBBLE_GESTURE_TYPE_UMA(kPermissionsPromptShownGesture,
kPermissionsPromptShownNoGesture,
gesture_type, request_type);
}
void PermissionUmaUtil::PermissionPromptResolved(
const std::vector<PermissionRequest*>& requests,
content::WebContents* web_contents,
PermissionAction permission_action,
PermissionPromptDisposition ui_disposition) {
std::string action_string;
switch (permission_action) {
case PermissionAction::GRANTED:
RecordPromptDecided(requests, /*accepted=*/true);
action_string = "Accepted";
break;
case PermissionAction::DENIED:
RecordPromptDecided(requests, /*accepted=*/false);
action_string = "Denied";
break;
case PermissionAction::DISMISSED:
action_string = "Dismissed";
break;
case PermissionAction::IGNORED:
action_string = "Ignored";
break;
default:
NOTREACHED();
break;
}
RecordEngagementMetric(requests, web_contents, action_string);
PermissionDecisionAutoBlocker* autoblocker =
PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
web_contents->GetBrowserContext());
for (PermissionRequest* request : requests) {
ContentSettingsType permission = request->GetContentSettingsType();
// TODO(timloh): We only record these metrics for permissions which use
// PermissionRequestImpl as the other subclasses don't support
// GetGestureType and GetContentSettingsType.
if (permission == ContentSettingsType::DEFAULT)
continue;
PermissionRequestGestureType gesture_type = request->GetGestureType();
const GURL& requesting_origin = request->GetOrigin();
RecordPermissionAction(permission, permission_action,
PermissionSourceUI::PROMPT, gesture_type,
ui_disposition, requesting_origin, web_contents,
web_contents->GetBrowserContext());
std::string priorDismissPrefix =
"Permissions.Prompt." + action_string + ".PriorDismissCount2.";
std::string priorIgnorePrefix =
"Permissions.Prompt." + action_string + ".PriorIgnoreCount2.";
RecordPermissionPromptPriorCount(
permission, priorDismissPrefix,
autoblocker->GetDismissCount(requesting_origin, permission));
RecordPermissionPromptPriorCount(
permission, priorIgnorePrefix,
autoblocker->GetIgnoreCount(requesting_origin, permission));
#if defined(OS_ANDROID)
if (permission == ContentSettingsType::GEOLOCATION &&
permission_action != PermissionAction::IGNORED) {
RecordWithBatteryBucket("Permissions.BatteryLevel." + action_string +
".Geolocation");
}
#endif
}
base::UmaHistogramEnumeration("Permissions.Action.WithDisposition." +
GetPromptDispositionString(ui_disposition),
permission_action, PermissionAction::NUM);
}
void PermissionUmaUtil::RecordPermissionPromptPriorCount(
ContentSettingsType permission,
const std::string& prefix,
int count) {
// The user is not prompted for this permissions, thus there is no prompt
// event to record a prior count for.
DCHECK_NE(ContentSettingsType::BACKGROUND_SYNC, permission);
// Expand UMA_HISTOGRAM_COUNTS_100 so that we can use a dynamically suffixed
// histogram name.
base::Histogram::FactoryGet(
prefix + PermissionUtil::GetPermissionString(permission), 1, 100, 50,
base::HistogramBase::kUmaTargetedHistogramFlag)
->Add(count);
}
#if defined(OS_ANDROID)
void PermissionUmaUtil::RecordWithBatteryBucket(const std::string& histogram) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_PermissionUmaUtil_recordWithBatteryBucket(
env, base::android::ConvertUTF8ToJavaString(env, histogram));
}
#endif
void PermissionUmaUtil::RecordInfobarDetailsExpanded(bool expanded) {
base::UmaHistogramBoolean("Permissions.Prompt.Infobar.DetailsExpanded",
expanded);
}
void PermissionUmaUtil::RecordMissingPermissionInfobarShouldShow(
bool should_show,
const std::vector<ContentSettingsType>& content_settings_types) {
for (const auto& content_settings_type : content_settings_types) {
base::UmaHistogramBoolean(
"Permissions.MissingOSLevelPermission.ShouldShow." +
PermissionUtil::GetPermissionString(content_settings_type),
should_show);
}
}
void PermissionUmaUtil::RecordMissingPermissionInfobarAction(
PermissionAction action,
const std::vector<ContentSettingsType>& content_settings_types) {
for (const auto& content_settings_type : content_settings_types) {
base::UmaHistogramEnumeration(
"Permissions.MissingOSLevelPermission.Action." +
PermissionUtil::GetPermissionString(content_settings_type),
action, PermissionAction::NUM);
}
}
PermissionUmaUtil::ScopedRevocationReporter::ScopedRevocationReporter(
content::BrowserContext* browser_context,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
PermissionSourceUI source_ui)
: browser_context_(browser_context),
primary_url_(primary_url),
secondary_url_(secondary_url),
content_type_(content_type),
source_ui_(source_ui) {
if (!primary_url_.is_valid() ||
(!secondary_url_.is_valid() && !secondary_url_.is_empty())) {
is_initially_allowed_ = false;
return;
}
HostContentSettingsMap* settings_map =
PermissionsClient::Get()->GetSettingsMap(browser_context_);
ContentSetting initial_content_setting = settings_map->GetContentSetting(
primary_url_, secondary_url_, content_type_, std::string());
is_initially_allowed_ = initial_content_setting == CONTENT_SETTING_ALLOW;
content_settings::SettingInfo setting_info;
settings_map->GetWebsiteSetting(primary_url, secondary_url, content_type_,
std::string(), &setting_info);
last_modified_date_ = settings_map->GetSettingLastModifiedDate(
setting_info.primary_pattern, setting_info.secondary_pattern,
content_type);
}
PermissionUmaUtil::ScopedRevocationReporter::ScopedRevocationReporter(
content::BrowserContext* browser_context,
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
PermissionSourceUI source_ui)
: ScopedRevocationReporter(
browser_context,
GURL(primary_pattern.ToString()),
GURL((secondary_pattern == ContentSettingsPattern::Wildcard())
? primary_pattern.ToString()
: secondary_pattern.ToString()),
content_type,
source_ui) {}
PermissionUmaUtil::ScopedRevocationReporter::~ScopedRevocationReporter() {
if (!is_initially_allowed_)
return;
HostContentSettingsMap* settings_map =
PermissionsClient::Get()->GetSettingsMap(browser_context_);
ContentSetting final_content_setting = settings_map->GetContentSetting(
primary_url_, secondary_url_, content_type_, std::string());
if (final_content_setting != CONTENT_SETTING_ALLOW) {
// PermissionUmaUtil takes origins, even though they're typed as GURL.
GURL requesting_origin = primary_url_.GetOrigin();
PermissionRevoked(content_type_, source_ui_, requesting_origin,
browser_context_);
if ((content_type_ == ContentSettingsType::GEOLOCATION ||
content_type_ == ContentSettingsType::MEDIASTREAM_CAMERA ||
content_type_ == ContentSettingsType::MEDIASTREAM_MIC) &&
!last_modified_date_.is_null()) {
RecordTimeElapsedBetweenGrantAndRevoke(
content_type_, base::Time::Now() - last_modified_date_);
}
}
}
void PermissionUmaUtil::RecordPermissionAction(
ContentSettingsType permission,
PermissionAction action,
PermissionSourceUI source_ui,
PermissionRequestGestureType gesture_type,
PermissionPromptDisposition ui_disposition,
const GURL& requesting_origin,
const content::WebContents* web_contents,
content::BrowserContext* browser_context) {
PermissionDecisionAutoBlocker* autoblocker =
PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
browser_context);
int dismiss_count =
autoblocker->GetDismissCount(requesting_origin, permission);
int ignore_count = autoblocker->GetIgnoreCount(requesting_origin, permission);
PermissionsClient::Get()->GetUkmSourceId(
browser_context, web_contents, requesting_origin,
base::BindOnce(
&RecordPermissionActionUkm, action, gesture_type, permission,
dismiss_count, ignore_count, source_ui, ui_disposition,
permission == ContentSettingsType::NOTIFICATIONS
? PermissionsClient::Get()
->HadThreeConsecutiveNotificationPermissionDenies(
browser_context)
: base::nullopt));
switch (permission) {
case ContentSettingsType::GEOLOCATION:
base::UmaHistogramEnumeration("Permissions.Action.Geolocation", action,
PermissionAction::NUM);
break;
case ContentSettingsType::NOTIFICATIONS:
base::UmaHistogramEnumeration("Permissions.Action.Notifications", action,
PermissionAction::NUM);
break;
case ContentSettingsType::MIDI_SYSEX:
base::UmaHistogramEnumeration("Permissions.Action.MidiSysEx", action,
PermissionAction::NUM);
break;
case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER:
base::UmaHistogramEnumeration("Permissions.Action.ProtectedMedia", action,
PermissionAction::NUM);
break;
case ContentSettingsType::MEDIASTREAM_MIC:
base::UmaHistogramEnumeration("Permissions.Action.AudioCapture", action,
PermissionAction::NUM);
break;
case ContentSettingsType::MEDIASTREAM_CAMERA:
base::UmaHistogramEnumeration("Permissions.Action.VideoCapture", action,
PermissionAction::NUM);
break;
case ContentSettingsType::PLUGINS:
base::UmaHistogramEnumeration("Permissions.Action.Flash", action,
PermissionAction::NUM);
break;
case ContentSettingsType::CLIPBOARD_READ_WRITE:
base::UmaHistogramEnumeration("Permissions.Action.ClipboardReadWrite",
action, PermissionAction::NUM);
break;
case ContentSettingsType::PAYMENT_HANDLER:
base::UmaHistogramEnumeration("Permissions.Action.PaymentHandler", action,
PermissionAction::NUM);
break;
case ContentSettingsType::NFC:
base::UmaHistogramEnumeration("Permissions.Action.Nfc", action,
PermissionAction::NUM);
break;
case ContentSettingsType::VR:
base::UmaHistogramEnumeration("Permissions.Action.VR", action,
PermissionAction::NUM);
break;
case ContentSettingsType::AR:
base::UmaHistogramEnumeration("Permissions.Action.AR", action,
PermissionAction::NUM);
break;
case ContentSettingsType::STORAGE_ACCESS:
base::UmaHistogramEnumeration("Permissions.Action.StorageAccess", action,
PermissionAction::NUM);
break;
case ContentSettingsType::CAMERA_PAN_TILT_ZOOM:
base::UmaHistogramEnumeration("Permissions.Action.CameraPanTiltZoom",
action, PermissionAction::NUM);
break;
case ContentSettingsType::WINDOW_PLACEMENT:
base::UmaHistogramEnumeration("Permissions.Action.WindowPlacement",
action, PermissionAction::NUM);
break;
case ContentSettingsType::FONT_ACCESS:
base::UmaHistogramEnumeration("Permissions.Action.FontAccess", action,
PermissionAction::NUM);
break;
case ContentSettingsType::IDLE_DETECTION:
base::UmaHistogramEnumeration("Permissions.Action.IdleDetection", action,
PermissionAction::NUM);
break;
// The user is not prompted for these permissions, thus there is no
// permission action recorded for them.
default:
NOTREACHED() << "PERMISSION "
<< PermissionUtil::GetPermissionString(permission)
<< " not accounted for";
}
}
// static
void PermissionUmaUtil::RecordPromptDecided(
const std::vector<PermissionRequest*>& requests,
bool accepted) {
DCHECK(!requests.empty());
PermissionRequestType request_type = PermissionRequestType::MULTIPLE;
PermissionRequestGestureType gesture_type =
PermissionRequestGestureType::UNKNOWN;
if (requests.size() == 1) {
request_type = requests[0]->GetPermissionRequestType();
gesture_type = requests[0]->GetGestureType();
}
if (accepted) {
PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptAccepted, request_type);
PERMISSION_BUBBLE_GESTURE_TYPE_UMA(kPermissionsPromptAcceptedGesture,
kPermissionsPromptAcceptedNoGesture,
gesture_type, request_type);
} else {
PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptDenied, request_type);
PERMISSION_BUBBLE_GESTURE_TYPE_UMA(kPermissionsPromptDeniedGesture,
kPermissionsPromptDeniedNoGesture,
gesture_type, request_type);
}
}
void PermissionUmaUtil::RecordTimeElapsedBetweenGrantAndUse(
ContentSettingsType type,
base::TimeDelta delta) {
base::UmaHistogramCustomCounts(
"Permissions.Usage.ElapsedTimeSinceGrant." +
PermissionUtil::GetPermissionString(type),
delta.InSeconds(), 1, base::TimeDelta::FromDays(365).InSeconds(), 100);
}
void PermissionUmaUtil::RecordTimeElapsedBetweenGrantAndRevoke(
ContentSettingsType type,
base::TimeDelta delta) {
base::UmaHistogramCustomCounts(
"Permissions.Revocation.ElapsedTimeSinceGrant." +
PermissionUtil::GetPermissionString(type),
delta.InSeconds(), 1, base::TimeDelta::FromDays(365).InSeconds(), 100);
}
} // namespace permissions