1
>
/*---------------------------------------------------------------------------------------------
userActivityService.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { disposableTimeout, RunOnceScheduler, runWhenGlobalIdle } from '../../../../base/common/async.js';
7
>
import { Emitter, Event } from '../../../../base/common/event.js';
8
>
import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
9
>
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
10
>
import { IInstantiationService, createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
11
>
import { userActivityRegistry } from './userActivityRegistry.js';
12
>
13
>
export interface IMarkActiveOptions {
14
>
whenHeldFor?: number;
15
>
/**
16
>
* Only consider this progress if the state is already active. Used to avoid
17
>
* background work from incorrectly marking the user as active (#237386)
18
>
*/
19
>
extendOnly?: boolean;
20
>
}
21
>
22
>
/**
23
>
* Service that observes user activity in the window.
24
>
*/
25
>
export interface IUserActivityService {
26
>
_serviceBrand: undefined;
27
>
28
>
/**
29
>
* Whether the user is currently active.
30
>
*/
31
>
readonly isActive: boolean;
32
>
33
>
/**
34
>
* Fires when the activity state changes.
35
>
*/
36
>
readonly onDidChangeIsActive: Event<boolean>;
37
>
38
>
/**
39
>
* Marks the user as being active until the Disposable is disposed of.
40
>
* Multiple consumers call this method; the user will only be considered
41
>
* inactive once all consumers have disposed of their Disposables.
42
>
*/
43
>
markActive(opts?: IMarkActiveOptions): IDisposable;
44
>
}
45
>
46
>
const MARK_INACTIVE_DEBOUNCE = 10_000;
47
>
48
>
export const IUserActivityService = createDecorator<IUserActivityService>('IUserActivityService');
49
>
50
>
export class UserActivityService extends Disposable implements IUserActivityService {
51
>
declare readonly _serviceBrand: undefined;
52
>
private readonly markInactive = this._register(new RunOnceScheduler(() => {
53
this.isActive = false;
54
this.changeEmitter.fire(false);
56
>
57
>
private readonly changeEmitter = this._register(new Emitter<boolean>);
58
>
private active = 0;
59
>
60
>
/**
61
>
* @inheritdoc
62
>
*
63
>
* Note: initialized to true, since the user just did something to open the
64
>
* window. The bundled DomActivityTracker will initially assume activity
65
>
* as well in order to unset this if the window gets abandoned.
66
>
*/
67
>
public isActive = true;
68
>
69
>
/** @inheritdoc */
70
>
readonly onDidChangeIsActive: Event<boolean> = this.changeEmitter.event;
71
>
72
>
constructor(@IInstantiationService instantiationService: IInstantiationService) {
73
>
super();
74
>
this._register(runWhenGlobalIdle(() => userActivityRegistry.take(this, instantiationService)));
75
>
}
76
>
77
>
/** @inheritdoc */
78
>
markActive(opts?: IMarkActiveOptions): IDisposable {
79
if (opts?.extendOnly && !this.isActive) {
80
return Disposable.None;