timeLimitsManager: Store screen time state on suspend/resume
There are two main changes in this commit: * Listen to the `prepare-for-sleep` signal from `LoginManager`, which is emitted just before suspending and just after resuming. When the signal is received, update the user’s screen time state (active or inactive), add a transition if necessary, and save the screen time history if necessary. * Factor the `preparingForSleep` property of `LoginManager` into the user’s screen time state, meaning that the user will be considered inactive between the system going for suspend and coming back from resume. The rest of the changes in the commit are boilerplate to allow for this functionality to be unit tested. Signed-off-by: Philip Withnall <pwithnall@gnome.org> Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/8185 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3643>
This commit is contained in:
parent
9dd5f7a8a8
commit
6a43b6f551
@ -1,6 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// Copyright 2024 GNOME Foundation, Inc.
|
||||
// Copyright 2024, 2025 GNOME Foundation, Inc.
|
||||
//
|
||||
// This is a GNOME Shell component to support screen time limits and statistics.
|
||||
//
|
||||
@ -84,13 +84,15 @@ function userStateToString(userState) {
|
||||
*
|
||||
* Active/Inactive time is based off the total time the user account has spent
|
||||
* logged in to at least one active session, not idle (and not locked, but
|
||||
* that’s a subset of idle time).
|
||||
* that’s a subset of idle time), and not suspended.
|
||||
* This corresponds to the `active` state from sd_uid_get_state()
|
||||
* (https://www.freedesktop.org/software/systemd/man/latest/sd_uid_get_state.html),
|
||||
* plus `IdleHint` from
|
||||
* https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html#User%20Objects.
|
||||
* https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html#User%20Objects,
|
||||
* plus `PreparingForSleep` from
|
||||
*.https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html#The%20Manager%20Object.
|
||||
* ‘Inactive’ time corresponds to all the other states from sd_uid_get_state(),
|
||||
* or if `IdleHint` is true.
|
||||
* or if `IdleHint` is true or if `PreparingForSleep` is true.
|
||||
*
|
||||
* All times within the class are handled in terms of wall/real clock time,
|
||||
* rather than monotonic time. This is because it’s necessary to continue
|
||||
@ -121,7 +123,7 @@ export const TimeLimitsManager = GObject.registerClass({
|
||||
'daily-limit-reached': {},
|
||||
},
|
||||
}, class TimeLimitsManager extends GObject.Object {
|
||||
constructor(historyFile, clock, loginUserFactory, settingsFactory) {
|
||||
constructor(historyFile, clock, loginManagerFactory, loginUserFactory, settingsFactory) {
|
||||
super();
|
||||
|
||||
// Allow these few bits of global state to be overridden for unit testing
|
||||
@ -143,6 +145,9 @@ export const TimeLimitsManager = GObject.registerClass({
|
||||
return timeChangeSource.attach(null);
|
||||
},
|
||||
};
|
||||
this._loginManagerFactory = loginManagerFactory ?? {
|
||||
new: LoginManager.getLoginManager,
|
||||
};
|
||||
this._loginUserFactory = loginUserFactory ?? {
|
||||
newAsync: () => {
|
||||
const loginManager = LoginManager.getLoginManager();
|
||||
@ -163,6 +168,7 @@ export const TimeLimitsManager = GObject.registerClass({
|
||||
this._state = TimeLimitsState.DISABLED;
|
||||
this._stateTransitions = [];
|
||||
this._cancellable = null;
|
||||
this._loginManager = null;
|
||||
this._loginUser = null;
|
||||
this._lastStateChangeTimeSecs = 0;
|
||||
this._timerId = 0;
|
||||
@ -252,6 +258,13 @@ export const TimeLimitsManager = GObject.registerClass({
|
||||
}
|
||||
|
||||
// Start listening for notifications to the user’s state.
|
||||
this._loginManager = this._loginManagerFactory.new();
|
||||
this._loginManager.connectObject(
|
||||
'prepare-for-sleep',
|
||||
() => this._updateUserState(true).catch(
|
||||
e => console.warn(`Failed to update user state: ${e.message}`)),
|
||||
this);
|
||||
|
||||
this._loginUser = await this._loginUserFactory.newAsync();
|
||||
this._loginUser.connectObject(
|
||||
'g-properties-changed',
|
||||
@ -277,6 +290,9 @@ export const TimeLimitsManager = GObject.registerClass({
|
||||
this._loginUser?.disconnectObject(this);
|
||||
this._loginUser = null;
|
||||
|
||||
this._loginManager?.disconnectObject(this);
|
||||
this._loginManager = null;
|
||||
|
||||
this._state = TimeLimitsState.DISABLED;
|
||||
this._lastStateChangeTimeSecs = 0;
|
||||
this.notify('state');
|
||||
@ -360,7 +376,9 @@ export const TimeLimitsManager = GObject.registerClass({
|
||||
}
|
||||
|
||||
_calculateUserStateFromLogind() {
|
||||
const isActive = this._loginUser.State === 'active' && !this._loginUser.IdleHint;
|
||||
const isActive = this._loginUser.State === 'active' &&
|
||||
!this._loginUser.IdleHint &&
|
||||
!this._loginManager.preparingForSleep;
|
||||
return isActive ? UserState.ACTIVE : UserState.INACTIVE;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// Copyright 2024 GNOME Foundation, Inc.
|
||||
// Copyright 2024, 2025 GNOME Foundation, Inc.
|
||||
//
|
||||
// This is a GNOME Shell component to support screen time limits and statistics.
|
||||
//
|
||||
@ -73,6 +73,9 @@ class TestHarness {
|
||||
|
||||
this._loginUserPropertiesChangedCallback = null;
|
||||
|
||||
this._currentPreparingForSleepState = false;
|
||||
this._loginManagerPrepareForSleepCallback = null;
|
||||
|
||||
// Create a fake history file containing the given contents. Or, if no
|
||||
// contents are given, reserve a distinct new history file name but then
|
||||
// delete it so it doesn’t exist for the manager.
|
||||
@ -87,6 +90,28 @@ class TestHarness {
|
||||
|
||||
// And a mock D-Bus proxy for logind.
|
||||
const harness = this;
|
||||
|
||||
class MockLoginManager {
|
||||
connectObject(signalName, callback, unusedObject) {
|
||||
if (signalName === 'prepare-for-sleep') {
|
||||
if (harness._loginManagerPrepareForSleepCallback !== null)
|
||||
fail('Duplicate prepare-for-sleep connection');
|
||||
harness._loginManagerPrepareForSleepCallback = callback;
|
||||
} else {
|
||||
// No-op for mock purposes
|
||||
}
|
||||
}
|
||||
|
||||
disconnectObject(unused) {
|
||||
// Very simple implementation for mock purposes
|
||||
harness._loginManagerPrepareForSleepCallback = null;
|
||||
}
|
||||
|
||||
get preparingForSleep() {
|
||||
return harness._currentPreparingForSleepState;
|
||||
}
|
||||
}
|
||||
|
||||
class MockLoginUser {
|
||||
connectObject(signalName, callback, unusedObject) {
|
||||
if (signalName === 'g-properties-changed') {
|
||||
@ -112,6 +137,7 @@ class TestHarness {
|
||||
}
|
||||
}
|
||||
|
||||
this._mockLoginManager = new MockLoginManager();
|
||||
this._mockLoginUser = new MockLoginUser();
|
||||
}
|
||||
|
||||
@ -223,6 +249,34 @@ class TestHarness {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pair of sleep and resume events to the event queue. This simulates
|
||||
* the machine being asleep (suspended) and then resumed after a period of
|
||||
* time. No other events should be inserted into the queue between these
|
||||
* two.
|
||||
*
|
||||
* This simulates the [D-Bus API for logind](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html#The%20Manager%20Object)
|
||||
* notifying to prepare for sleep at date/time `timeStr`, then sleeping,
|
||||
* then notifying that the machine has resumed from sleep at date/time
|
||||
* `timeStr` plus `duration` (in seconds).
|
||||
*
|
||||
* @param {string} timeStr Date/Time the prepare-for-sleep event happens,
|
||||
* in ISO 8601 format.
|
||||
* @param {number} duration Duration of the sleep/suspend period, in seconds
|
||||
*/
|
||||
addSleepAndResumeEvent(timeStr, duration) {
|
||||
this._insertEvent({
|
||||
type: 'preparing-for-sleep-state-change',
|
||||
time: TestHarness.timeStrToSecs(timeStr),
|
||||
newPreparingForSleepState: true,
|
||||
});
|
||||
this._insertEvent({
|
||||
type: 'preparing-for-sleep-state-change',
|
||||
time: TestHarness.timeStrToSecs(timeStr) + duration,
|
||||
newPreparingForSleepState: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a login user state change event to the event queue. This simulates
|
||||
* the [D-Bus API for logind](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html#User%20Objects)
|
||||
@ -408,6 +462,24 @@ class TestHarness {
|
||||
this._currentTimeSecs = TestHarness.timeStrToSecs(timeStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mock login manager factory for use in the `TimeLimitsManager` under
|
||||
* test. This is an object providing a constructor for the objects returned
|
||||
* by `LoginManager.getLoginManager()`. This is roughly a wrapper around the
|
||||
* [`org.freedesktop.login1.Manager` D-Bus API](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html#The%20Manager%20Object).
|
||||
* Each constructor returns a basic implementation of the manager which uses
|
||||
* the current state from `TestHarness`.
|
||||
*
|
||||
* This has an extra layer of indirection to match `mockSettingsFactory`.
|
||||
*/
|
||||
get mockLoginManagerFactory() {
|
||||
return {
|
||||
new: () => {
|
||||
return this._mockLoginManager;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mock login user factory for use in the `TimeLimitsManager` under
|
||||
* test. This is an object providing constructors for `LoginUser` objects,
|
||||
@ -503,6 +575,12 @@ class TestHarness {
|
||||
if (this._timeChangeNotify)
|
||||
this._timeChangeNotify();
|
||||
break;
|
||||
case 'preparing-for-sleep-state-change':
|
||||
this._currentPreparingForSleepState = event.newPreparingForSleepState;
|
||||
|
||||
if (this._loginManagerPrepareForSleepCallback)
|
||||
this._loginManagerPrepareForSleepCallback(this._currentPreparingForSleepState);
|
||||
break;
|
||||
case 'login-user-state-change':
|
||||
this._currentUserState = event.newUserState;
|
||||
this._currentUserIdleHint = event.newUserIdleHint;
|
||||
@ -598,7 +676,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.DISABLED);
|
||||
harness.expectState('2024-06-01T15:00:00Z', timeLimitsManager, TimeLimitsState.DISABLED);
|
||||
@ -622,7 +700,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.addSettingsChangeEvent('2024-06-01T11:00:00Z',
|
||||
@ -657,7 +735,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.expectProperties('2024-06-01T13:59:59Z', timeLimitsManager, {
|
||||
@ -679,7 +757,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T00:30:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T00:30:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.expectProperties('2024-06-01T01:29:59Z', timeLimitsManager, {
|
||||
@ -701,7 +779,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.expectProperties('2024-06-01T13:59:59Z', timeLimitsManager, {
|
||||
@ -734,7 +812,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.expectProperties('2024-06-01T15:00:00Z', timeLimitsManager, {
|
||||
@ -774,7 +852,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// Run until the limit is reached.
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
@ -832,7 +910,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
]));
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// The existing history file (above) lists two active periods,
|
||||
// 07:30–08:00 and 08:30–09:30 that morning. So the user should have
|
||||
@ -868,7 +946,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
]));
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// The existing history file (above) lists one active period,
|
||||
// 04:30–08:50 that morning. So the user should have no time left today.
|
||||
@ -907,7 +985,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
}, invalidHistoryFileContents);
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// The existing history file (above) is invalid or a no-op and
|
||||
// should be ignored.
|
||||
@ -953,7 +1031,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
]));
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// The existing history file (above) lists two active periods,
|
||||
// one of which is a long time ago and the other is ‘this’ morning in
|
||||
@ -1018,7 +1096,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
]));
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// The existing history file (above) lists one active period,
|
||||
// 04:30–08:50 that morning IN THE YEAR 3000. This could have resulted
|
||||
@ -1053,7 +1131,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
]));
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.addSettingsChangeEvent('2024-06-01T10:00:02Z',
|
||||
@ -1089,7 +1167,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
]));
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.expectState('2024-06-01T14:00:01Z', timeLimitsManager, TimeLimitsState.LIMIT_REACHED);
|
||||
@ -1127,7 +1205,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// Use up 2h of the daily limit.
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
@ -1164,7 +1242,7 @@ describe('Time limits manager', () => {
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// Use up 2h of the daily limit.
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
@ -1191,4 +1269,34 @@ describe('Time limits manager', () => {
|
||||
|
||||
harness.run();
|
||||
});
|
||||
|
||||
it('doesn’t count usage when asleep/suspended', () => {
|
||||
const harness = new TestHarness({
|
||||
'org.gnome.desktop.screen-time-limits': {
|
||||
'history-enabled': true,
|
||||
'daily-limit-enabled': true,
|
||||
'daily-limit-seconds': 4 * 60 * 60,
|
||||
},
|
||||
});
|
||||
harness.initializeMockClock('2024-06-01T10:00:00Z');
|
||||
const timeLimitsManager = new TimeLimitsManager.TimeLimitsManager(harness.mockHistoryFile, harness.mockClock, harness.mockLoginManagerFactory, harness.mockLoginUserFactory, harness.mockSettingsFactory);
|
||||
|
||||
// Use up 2h of the daily limit.
|
||||
harness.expectState('2024-06-01T10:00:01Z', timeLimitsManager, TimeLimitsState.ACTIVE);
|
||||
harness.expectProperties('2024-06-01T12:00:00Z', timeLimitsManager, {
|
||||
'state': TimeLimitsState.ACTIVE,
|
||||
'dailyLimitTime': TestHarness.timeStrToSecs('2024-06-01T14:00:00Z'),
|
||||
});
|
||||
|
||||
// Sleep for 3h and that shouldn’t use up limit time.
|
||||
harness.addSleepAndResumeEvent('2024-06-01T12:00:01Z', 3 * 60 * 60);
|
||||
harness.expectProperties('2024-06-01T15:00:02Z', timeLimitsManager, {
|
||||
'state': TimeLimitsState.ACTIVE,
|
||||
'dailyLimitTime': TestHarness.timeStrToSecs('2024-06-01T17:00:00Z'),
|
||||
});
|
||||
|
||||
harness.shutdownManager('2024-06-01T15:20:00Z', timeLimitsManager);
|
||||
|
||||
harness.run();
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user