Commit 828f6e4f authored by Olivier Robin's avatar Olivier Robin Committed by Commit Bot

Report IOS.Incognito.TimeSpent

This histogram report the time incognito profile is on screen.

Change-Id: Idef5b1602b941ae98dabad406ca81fd246d7bf8b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2470573
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarBrian White <bcwhite@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Reviewed-by: default avatarChris Lu <thegreenfrog@chromium.org>
Cr-Commit-Position: refs/heads/master@{#819003}
parent 4ccbf456
......@@ -219,7 +219,7 @@ source_set("app_internal") {
"//ios/chrome/browser/history",
"//ios/chrome/browser/main",
"//ios/chrome/browser/memory",
"//ios/chrome/browser/metrics:metrics",
"//ios/chrome/browser/metrics",
"//ios/chrome/browser/metrics:metrics_internal",
"//ios/chrome/browser/net",
"//ios/chrome/browser/ntp:features",
......
......@@ -69,6 +69,7 @@
#import "ios/chrome/browser/main/browser_list_factory.h"
#import "ios/chrome/browser/memory/memory_debugger_manager.h"
#include "ios/chrome/browser/metrics/first_user_action_recorder.h"
#import "ios/chrome/browser/metrics/incognito_usage_app_state_agent.h"
#import "ios/chrome/browser/metrics/window_configuration_recorder.h"
#import "ios/chrome/browser/net/cookie_util.h"
#import "ios/chrome/browser/omaha/omaha_service.h"
......@@ -617,6 +618,7 @@ void MainControllerAuthenticationServiceDelegate::ClearBrowsingData(
// Create app state agents.
[appState addAgent:[[ContentSuggestionsSchedulerAppAgent alloc] init]];
[appState addAgent:[[IncognitoUsageAppStateAgent alloc] init]];
}
- (id<BrowserInterfaceProvider>)interfaceProvider {
......
......@@ -21,6 +21,8 @@ source_set("chrome_browser_state_client") {
source_set("metrics") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"incognito_usage_app_state_agent.h",
"incognito_usage_app_state_agent.mm",
"incognito_web_state_observer.h",
"incognito_web_state_observer.mm",
"ios_chrome_default_browser_metrics_provider.h",
......@@ -70,6 +72,7 @@ source_set("metrics") {
"//components/variations",
"//components/variations/service",
"//components/version_info",
"//ios/chrome/app/application_delegate:app_state_header",
"//ios/chrome/browser",
"//ios/chrome/browser/browser_state",
"//ios/chrome/browser/crash_report",
......@@ -82,6 +85,7 @@ source_set("metrics") {
"//ios/chrome/browser/sync",
"//ios/chrome/browser/tabs",
"//ios/chrome/browser/translate",
"//ios/chrome/browser/ui/main:scene_state_header",
"//ios/chrome/browser/ui/overscroll_actions",
"//ios/chrome/browser/ui/util:multiwindow_util",
"//ios/chrome/browser/ui/whats_new:utils",
......@@ -102,6 +106,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"chrome_browser_state_client_unittest.mm",
"incognito_usage_app_state_agent_unittest.mm",
"ios_chrome_default_browser_metrics_provider_unittest.mm",
"ios_chrome_metrics_service_accessor_unittest.cc",
"ios_chrome_metrics_service_client_unittest.mm",
......@@ -124,8 +129,10 @@ source_set("unit_tests") {
"//components/ukm",
"//components/ukm:test_support",
"//components/version_info",
"//ios/chrome/app/application_delegate:app_state_header",
"//ios/chrome/browser",
"//ios/chrome/browser/browser_state:test_support",
"//ios/chrome/browser/ui/main:scene_state_header",
"//ios/chrome/browser/ui/whats_new:utils",
"//ios/chrome/browser/web:test_support",
"//ios/chrome/test:test_support",
......@@ -135,6 +142,7 @@ source_set("unit_tests") {
"//ios/web/public/test/fakes",
"//net:test_support",
"//testing/gtest",
"//third_party/ocmock",
]
}
......
// Copyright 2020 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.
#ifndef IOS_CHROME_BROWSER_METRICS_INCOGNITO_USAGE_APP_STATE_AGENT_H_
#define IOS_CHROME_BROWSER_METRICS_INCOGNITO_USAGE_APP_STATE_AGENT_H_
#import "ios/chrome/app/application_delegate/app_state_agent.h"
// The agent that logs the length of continuous usage of incognito.
// Any normal/incognito transition lasting less than 10 seconds will be ignored.
@interface IncognitoUsageAppStateAgent : NSObject <AppStateAgent>
@end
#endif // IOS_CHROME_BROWSER_METRICS_INCOGNITO_USAGE_APP_STATE_AGENT_H_
// Copyright 2020 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.
#import "ios/chrome/browser/metrics/incognito_usage_app_state_agent.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#import "ios/chrome/app/application_delegate/app_state.h"
#import "ios/chrome/browser/ui/main/scene_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Minimum amount of time for a normal/incognito transition to be considered.
const int kMinimumDelayInSeconds = 10;
}
@interface IncognitoUsageAppStateAgent () <AppStateObserver, SceneStateObserver>
// Observed app state.
@property(nonatomic, weak) AppState* appState;
@property(nonatomic, assign) BOOL incognitoContentVisible;
@property(nonatomic, assign) base::TimeTicks incognitoUsageStart;
@property(nonatomic, assign) base::TimeTicks incognitoUsageEnd;
@end
@implementation IncognitoUsageAppStateAgent
- (instancetype)init {
self = [super init];
if (self) {
[NSNotificationCenter.defaultCenter
addObserver:self
selector:@selector(applicationWillTerminate)
name:UIApplicationWillTerminateNotification
object:nil];
}
return self;
}
- (BOOL)checkIncognitoContentVisible {
for (SceneState* scene in self.appState.connectedScenes) {
if (scene.incognitoContentVisible &&
scene.activationLevel >= SceneActivationLevelForegroundInactive) {
return YES;
}
}
return NO;
}
- (void)reportIncognitoUsageTime {
DCHECK(!self.incognitoUsageStart.is_null());
DCHECK(!self.incognitoUsageEnd.is_null());
base::TimeDelta duration = self.incognitoUsageEnd - self.incognitoUsageStart;
if (duration.InSecondsF() < kMinimumDelayInSeconds) {
return;
}
base::UmaHistogramCustomTimes(
"IOS.Incognito.TimeSpent", duration, base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromSeconds(86400 /* secs per day */), 50);
self.incognitoUsageStart = base::TimeTicks();
self.incognitoUsageEnd = base::TimeTicks();
}
- (void)updateIncognitoContentVisible {
BOOL incognitoContentVisible = [self checkIncognitoContentVisible];
if (self.incognitoContentVisible == incognitoContentVisible) {
return;
}
self.incognitoContentVisible = incognitoContentVisible;
if (incognitoContentVisible) {
base::TimeTicks now = base::TimeTicks::Now();
if (!self.incognitoUsageEnd.is_null() &&
(now - self.incognitoUsageEnd).InSecondsF() < kMinimumDelayInSeconds) {
// The pausing of incognito is too short, resume session.
self.incognitoUsageEnd = base::TimeTicks();
} else {
// Incognito has been paused for a long time. This is a new session.
if (!self.incognitoUsageEnd.is_null() &&
!self.incognitoUsageStart.is_null() &&
(self.incognitoUsageEnd - self.incognitoUsageStart).InSecondsF() >=
kMinimumDelayInSeconds) {
// There was a previous session to report.
[self reportIncognitoUsageTime];
}
self.incognitoUsageStart = base::TimeTicks::Now();
}
} else {
base::TimeTicks now = base::TimeTicks::Now();
if (!self.incognitoUsageStart.is_null() &&
(now - self.incognitoUsageStart).InSecondsF() >=
kMinimumDelayInSeconds) {
self.incognitoUsageEnd = now;
} else {
// This incognito session was too short.
self.incognitoUsageStart = base::TimeTicks();
}
}
}
- (void)applicationWillTerminate {
if (self.incognitoContentVisible) {
self.incognitoUsageEnd = base::TimeTicks::Now();
}
if (!self.incognitoUsageEnd.is_null() &&
!self.incognitoUsageStart.is_null() &&
(self.incognitoUsageEnd - self.incognitoUsageStart).InSecondsF() >=
kMinimumDelayInSeconds) {
[self reportIncognitoUsageTime];
}
}
#pragma mark - AppStateAgent
- (void)setAppState:(AppState*)appState {
// This should only be called once!
DCHECK(!_appState);
_appState = appState;
[appState addObserver:self];
}
#pragma mark - AppStateObserver
- (void)appState:(AppState*)appState sceneConnected:(SceneState*)sceneState {
[sceneState addObserver:self];
[self updateIncognitoContentVisible];
}
#pragma mark - SceneStateObserver
- (void)sceneState:(SceneState*)sceneState
transitionedToActivationLevel:(SceneActivationLevel)level {
if (sceneState.incognitoContentVisible) {
[self updateIncognitoContentVisible];
}
}
- (void)sceneState:(SceneState*)sceneState
isDisplayingIncognitoContent:(BOOL)level {
if (sceneState.activationLevel >= SceneActivationLevelForegroundInactive) {
[self updateIncognitoContentVisible];
}
}
@end
......@@ -156,6 +156,15 @@
}
}
- (void)setIncognitoContentVisible:(BOOL)incognitoContentVisible {
if (incognitoContentVisible == _incognitoContentVisible) {
return;
}
_incognitoContentVisible = incognitoContentVisible;
[self.observers sceneState:self
isDisplayingIncognitoContent:incognitoContentVisible];
}
- (void)setPendingUserActivity:(NSUserActivity*)pendingUserActivity {
_pendingUserActivity = pendingUserActivity;
[self.observers sceneState:self receivedUserActivity:pendingUserActivity];
......
......@@ -35,6 +35,9 @@ enum SceneActivationLevel : NSUInteger;
// Notifies that a new activity request has been received.
- (void)sceneState:(SceneState*)sceneState
receivedUserActivity:(NSUserActivity*)userActivity;
// Notifies that the scene switched between incognito/normal mode.
- (void)sceneState:(SceneState*)sceneState
isDisplayingIncognitoContent:(BOOL)incognitoContentVisible;
@end
......
......@@ -357,6 +357,16 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary>
</histogram>
<histogram name="IOS.Incognito.TimeSpent" units="ms" expires_after="2020-12-25">
<owner>olivierrobin@chromium.org</owner>
<owner>thegreenfrog@chromium.org</owner>
<summary>
The time incognito profile is displayed to the user. Incognito sessions
during less than 10 seconds are not reported. Incognito session paused for
less than 10 seconds is resumed.
</summary>
</histogram>
<histogram name="IOS.IPHBubbleDismissalReason" enum="BubbleDismissalReason"
expires_after="M77">
<owner>pkl@chromium.org</owner>
......
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