2
* Copyright (C) 2019 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
13
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
* THE POSSIBILITY OF SUCH DAMAGE.
26
WI.TabActivityDiagnosticEventRecorder = class TabActivityDiagnosticEventRecorder extends WI.DiagnosticEventRecorder
28
constructor(controller)
30
super("TabActivity", controller);
32
this._inspectorHasFocus = true;
33
this._lastUserInteractionTimestamp = undefined;
35
this._eventSamplingTimerIdentifier = undefined;
36
this._initialDelayBeforeSamplingTimerIdentifier = undefined;
42
static get eventSamplingInterval() { return 60 * 1000; }
43
static get initialDelayBeforeSamplingInterval() { return 10 * 1000; }
52
window.addEventListener("focus", this, options);
53
window.addEventListener("blur", this, options);
54
window.addEventListener("keydown", this, options);
55
window.addEventListener("mousedown", this, options);
57
// If it's been less than 10 seconds since the frontend loaded, wait a bit.
58
if (performance.now() - WI.frontendCompletedLoadTimestamp < TabActivityDiagnosticEventRecorder.initialDelayBeforeSamplingInterval)
59
this._startInitialDelayBeforeSamplingTimer();
61
this._startEventSamplingTimer();
70
window.removeEventListener("focus", this, options);
71
window.removeEventListener("blur", this, options);
72
window.removeEventListener("keydown", this, options);
73
window.removeEventListener("mousedown", this, options);
75
this._stopInitialDelayBeforeSamplingTimer();
76
this._stopEventSamplingTimer();
86
this._handleWindowFocus(event);
89
this._handleWindowBlur(event);
92
this._handleWindowKeyDown(event);
95
this._handleWindowMouseDown(event);
102
_startInitialDelayBeforeSamplingTimer()
104
if (this._initialDelayBeforeSamplingTimerIdentifier) {
105
clearTimeout(this._initialDelayBeforeSamplingTimerIdentifier);
106
this._initialDelayBeforeSamplingTimerIdentifier = undefined;
109
// All intervals are in milliseconds.
110
let maximumInitialDelay = TabActivityDiagnosticEventRecorder.initialDelayBeforeSamplingInterval;
111
let elapsedTime = performance.now() - WI.frontendCompletedLoadTimestamp;
112
let remainingTime = maximumInitialDelay - elapsedTime;
113
let initialDelay = Number.constrain(remainingTime, 0, maximumInitialDelay);
114
this._initialDelayBeforeSamplingTimerIdentifier = setTimeout(this._sampleCurrentTabActivity.bind(this), initialDelay);
117
_stopInitialDelayBeforeSamplingTimer()
119
if (this._initialDelayBeforeSamplingTimerIdentifier) {
120
clearTimeout(this._initialDelayBeforeSamplingTimerIdentifier);
121
this._initialDelayBeforeSamplingTimerIdentifier = undefined;
125
_startEventSamplingTimer()
127
if (this._eventSamplingTimerIdentifier) {
128
clearTimeout(this._eventSamplingTimerIdentifier);
129
this._eventSamplingTimerIdentifier = undefined;
132
this._eventSamplingTimerIdentifier = setTimeout(this._sampleCurrentTabActivity.bind(this), TabActivityDiagnosticEventRecorder.eventSamplingInterval);
135
_stopEventSamplingTimer()
137
if (this._eventSamplingTimerIdentifier) {
138
clearTimeout(this._eventSamplingTimerIdentifier);
139
this._eventSamplingTimerIdentifier = undefined;
143
_sampleCurrentTabActivity()
145
// Set up the next timer first so later code can bail out if there's nothing to do.
146
this._stopEventSamplingTimer();
147
this._stopInitialDelayBeforeSamplingTimer();
148
this._startEventSamplingTimer();
150
let intervalSinceLastUserInteraction = performance.now() - this._lastUserInteractionTimestamp;
151
if (intervalSinceLastUserInteraction > TabActivityDiagnosticEventRecorder.eventSamplingInterval) {
152
if (WI.settings.debugAutoLogDiagnosticEvents.valueRespectingDebugUIAvailability)
153
console.log("TabActivity: sample not reported, last user interaction was %.1f seconds ago.".format(intervalSinceLastUserInteraction / 1000));
157
let selectedTabContentView = WI.tabBrowser.selectedTabContentView;
158
console.assert(selectedTabContentView);
159
if (!selectedTabContentView)
162
let tabType = selectedTabContentView.type;
163
let interval = TabActivityDiagnosticEventRecorder.eventSamplingInterval / 1000;
164
this.logDiagnosticEvent(this.name, {tabType, interval});
167
_didObserveUserInteraction()
169
if (!this._inspectorHasFocus)
172
this._lastUserInteractionTimestamp = performance.now();
175
_handleWindowFocus(event)
177
if (event.target !== window)
180
this._inspectorHasFocus = true;
183
_handleWindowBlur(event)
185
if (event.target !== window)
188
this._inspectorHasFocus = false;
191
_handleWindowKeyDown(event)
193
this._didObserveUserInteraction();
196
_handleWindowMouseDown(event)
198
this._didObserveUserInteraction();