blob: a87d343b7f0c91a9fec5f9efc156be9343a60000 [file] [log] [blame]
// 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/pageload_foreground_duration_tab_helper.h"
#import <UIKit/UIKit.h>
#include "components/ukm/ios/ukm_url_recorder.h"
#import "ios/web/public/navigation/navigation_context.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
WEB_STATE_USER_DATA_KEY_IMPL(PageloadForegroundDurationTabHelper)
PageloadForegroundDurationTabHelper::PageloadForegroundDurationTabHelper(
web::WebState* web_state)
: web_state_(web_state), scoped_observer_(this) {
DCHECK(web_state);
scoped_observer_.Add(web_state);
background_notification_observer_ = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationDidEnterBackgroundNotification
object:nil
queue:nil
usingBlock:^(NSNotification* notification) {
this->UpdateForAppDidBackground();
}];
foreground_notification_observer_ = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationWillEnterForegroundNotification
object:nil
queue:nil
usingBlock:^(NSNotification* notification) {
this->UpdateForAppWillForeground();
}];
}
PageloadForegroundDurationTabHelper::~PageloadForegroundDurationTabHelper() {
NSNotificationCenter* default_center = [NSNotificationCenter defaultCenter];
[default_center removeObserver:foreground_notification_observer_];
[default_center removeObserver:background_notification_observer_];
}
void PageloadForegroundDurationTabHelper::UpdateForAppWillForeground() {
// Return early if not currently active WebState.
if (!web_state_->IsVisible())
return;
last_time_shown_ = base::TimeTicks::Now();
currently_recording_ = true;
}
void PageloadForegroundDurationTabHelper::UpdateForAppDidBackground() {
// Return early if not currently active WebState.
if (!web_state_->IsVisible())
return;
RecordUkmIfInForeground();
}
void PageloadForegroundDurationTabHelper::WasShown(web::WebState* web_state) {
if (!currently_recording_) {
last_time_shown_ = base::TimeTicks::Now();
currently_recording_ = true;
}
}
void PageloadForegroundDurationTabHelper::WasHidden(web::WebState* web_state) {
RecordUkmIfInForeground();
}
void PageloadForegroundDurationTabHelper::DidStartNavigation(
web::WebState* web_state,
web::NavigationContext* navigation_context) {
DCHECK_EQ(web_state_, web_state);
// Do not start recording if the WebState is not visible. This is important to
// not record for pre-rendering in the omnibox.
// Do not log as end of recording for the current page session if the
// navigation is same-document.
if (!web_state_->IsVisible() || navigation_context->IsSameDocument())
return;
if (currently_recording_)
RecordUkmIfInForeground();
currently_recording_ = true;
last_time_shown_ = base::TimeTicks::Now();
}
void PageloadForegroundDurationTabHelper::DidFinishNavigation(
web::WebState* web_state,
web::NavigationContext* navigation_context) {
DCHECK_EQ(web_state_, web_state);
if (!web_state_->IsVisible() || navigation_context->IsSameDocument()) {
// Do not start recording if the WebState is not visible. This is important
// to not record for pre-rendering in the omnibox. Do not log successful
// navigation if it is same-document.
return;
}
int has_committed = navigation_context->HasCommitted() ? 1 : 0;
ukm::SourceId source_id = ukm::GetSourceIdForWebStateDocument(web_state_);
if (source_id != ukm::kInvalidSourceId) {
ukm::builders::MainFrameNavigation(source_id)
.SetDidCommit(has_committed)
.Record(ukm::UkmRecorder::Get());
}
}
void PageloadForegroundDurationTabHelper::RenderProcessGone(
web::WebState* web_state) {
DCHECK_EQ(web_state_, web_state);
if (!web_state_->IsVisible())
return;
RecordUkmIfInForeground();
}
void PageloadForegroundDurationTabHelper::WebStateDestroyed(
web::WebState* web_state) {
DCHECK_EQ(web_state_, web_state);
RecordUkmIfInForeground();
scoped_observer_.Remove(web_state);
web_state_ = nullptr;
}
void PageloadForegroundDurationTabHelper::RecordUkmIfInForeground() {
if (!currently_recording_)
return;
currently_recording_ = false;
base::TimeDelta foreground_duration =
base::TimeTicks::Now() - last_time_shown_;
ukm::SourceId source_id = ukm::GetSourceIdForWebStateDocument(web_state_);
if (source_id != ukm::kInvalidSourceId) {
ukm::builders::PageForegroundSession(source_id)
.SetForegroundDuration(foreground_duration.InMilliseconds())
.Record(ukm::UkmRecorder::Get());
}
}