1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "../InputDeviceMetricsCollector.h"
18
19 #include <NotifyArgsBuilders.h>
20 #include <gtest/gtest.h>
21 #include <input/InputEventBuilders.h>
22 #include <linux/input.h>
23
24 #include <array>
25 #include <tuple>
26
27 #include "TestInputListener.h"
28
29 namespace android {
30
31 using std::chrono_literals::operator""ns;
32 using std::chrono::nanoseconds;
33
34 namespace {
35
36 constexpr auto USAGE_TIMEOUT = 8765309ns;
37 constexpr auto TIME = 999999ns;
38
39 constexpr int32_t DEVICE_ID = 3;
40 constexpr int32_t DEVICE_ID_2 = 4;
41 constexpr int32_t VID = 0xFEED;
42 constexpr int32_t PID = 0xDEAD;
43 constexpr int32_t VERSION = 0xBEEF;
44 const std::string DEVICE_NAME = "Half Dome";
45 const std::string LOCATION = "California";
46 const std::string UNIQUE_ID = "Yosemite";
47 constexpr uint32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN;
48 constexpr uint32_t STYLUS = AINPUT_SOURCE_STYLUS;
49
generateTestIdentifier(int32_t id=DEVICE_ID)50 InputDeviceIdentifier generateTestIdentifier(int32_t id = DEVICE_ID) {
51 InputDeviceIdentifier identifier;
52 identifier.name = DEVICE_NAME + "_" + std::to_string(id);
53 identifier.location = LOCATION;
54 identifier.uniqueId = UNIQUE_ID;
55 identifier.vendor = VID;
56 identifier.product = PID;
57 identifier.version = VERSION;
58 identifier.bus = BUS_USB;
59 return identifier;
60 }
61
generateTestDeviceInfo(int32_t id=DEVICE_ID,uint32_t sources=TOUCHSCREEN|STYLUS)62 InputDeviceInfo generateTestDeviceInfo(int32_t id = DEVICE_ID,
63 uint32_t sources = TOUCHSCREEN | STYLUS) {
64 auto info = InputDeviceInfo();
65 info.initialize(id, /*generation=*/1, /*controllerNumber=*/1, generateTestIdentifier(id),
66 "alias", /*isExternal=*/false, /*hasMic=*/false, ui::LogicalDisplayId::INVALID);
67 info.addSource(sources);
68 return info;
69 }
70
71 const InputDeviceInfo TOUCHSCREEN_STYLUS_INFO = generateTestDeviceInfo(DEVICE_ID);
72 const InputDeviceInfo SECOND_TOUCHSCREEN_STYLUS_INFO = generateTestDeviceInfo(DEVICE_ID_2);
73
uids(std::initializer_list<int32_t> vals)74 std::set<gui::Uid> uids(std::initializer_list<int32_t> vals) {
75 std::set<gui::Uid> set;
76 for (const auto val : vals) {
77 set.emplace(val);
78 }
79 return set;
80 }
81
82 } // namespace
83
84 // --- InputDeviceMetricsCollectorTest ---
85
86 class InputDeviceMetricsCollectorTest : public testing::Test, public InputDeviceMetricsLogger {
87 protected:
88 TestInputListener mTestListener;
89 InputDeviceMetricsCollector mMetricsCollector{mTestListener, *this, USAGE_TIMEOUT};
90
assertUsageLogged(const InputDeviceInfo & info,nanoseconds duration,std::optional<SourceUsageBreakdown> sourceBreakdown={},std::optional<UidUsageBreakdown> uidBreakdown={})91 void assertUsageLogged(const InputDeviceInfo& info, nanoseconds duration,
92 std::optional<SourceUsageBreakdown> sourceBreakdown = {},
93 std::optional<UidUsageBreakdown> uidBreakdown = {}) {
94 ASSERT_GE(mLoggedUsageSessions.size(), 1u);
95 const auto& [loggedInfo, report] = *mLoggedUsageSessions.begin();
96 const auto& i = info.getIdentifier();
97 ASSERT_EQ(info.getId(), loggedInfo.deviceId);
98 ASSERT_EQ(i.vendor, loggedInfo.vendor);
99 ASSERT_EQ(i.product, loggedInfo.product);
100 ASSERT_EQ(i.version, loggedInfo.version);
101 ASSERT_EQ(i.bus, loggedInfo.bus);
102 ASSERT_EQ(info.getUsiVersion().has_value(), loggedInfo.isUsiStylus);
103 ASSERT_EQ(duration, report.usageDuration);
104 if (sourceBreakdown) {
105 ASSERT_EQ(sourceBreakdown, report.sourceBreakdown);
106 }
107 if (uidBreakdown) {
108 ASSERT_EQ(uidBreakdown, report.uidBreakdown);
109 }
110 mLoggedUsageSessions.erase(mLoggedUsageSessions.begin());
111 }
112
assertUsageNotLogged()113 void assertUsageNotLogged() { ASSERT_TRUE(mLoggedUsageSessions.empty()); }
114
setCurrentTime(nanoseconds time)115 void setCurrentTime(nanoseconds time) { mCurrentTime = time; }
116
currentTime() const117 nsecs_t currentTime() const { return mCurrentTime.count(); }
118
generateMotionArgs(int32_t deviceId,uint32_t source=AINPUT_SOURCE_TOUCHSCREEN,std::vector<ToolType> toolTypes={ToolType::FINGER})119 NotifyMotionArgs generateMotionArgs(int32_t deviceId,
120 uint32_t source = AINPUT_SOURCE_TOUCHSCREEN,
121 std::vector<ToolType> toolTypes = {ToolType::FINGER}) {
122 MotionArgsBuilder builder(AMOTION_EVENT_ACTION_MOVE, source);
123 for (size_t i = 0; i < toolTypes.size(); i++) {
124 builder.pointer(PointerBuilder(i, toolTypes[i]));
125 }
126 return builder.deviceId(deviceId)
127 .eventTime(mCurrentTime.count())
128 .downTime(mCurrentTime.count())
129 .build();
130 }
131
132 private:
133 std::vector<std::tuple<MetricsDeviceInfo, DeviceUsageReport>> mLoggedUsageSessions;
134 nanoseconds mCurrentTime{TIME};
135
getCurrentTime()136 nanoseconds getCurrentTime() override { return mCurrentTime; }
137
logInputDeviceUsageReported(const MetricsDeviceInfo & info,const DeviceUsageReport & report)138 void logInputDeviceUsageReported(const MetricsDeviceInfo& info,
139 const DeviceUsageReport& report) override {
140 mLoggedUsageSessions.emplace_back(info, report);
141 }
142 };
143
TEST_F(InputDeviceMetricsCollectorTest,DontLogUsageWhenDeviceNotRegistered)144 TEST_F(InputDeviceMetricsCollectorTest, DontLogUsageWhenDeviceNotRegistered) {
145 // Device was used.
146 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
147 mTestListener.assertNotifyMotionWasCalled();
148 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
149
150 // Device was used again after the usage timeout expired, but we still don't log usage.
151 setCurrentTime(TIME + USAGE_TIMEOUT);
152 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
153 mTestListener.assertNotifyMotionWasCalled();
154 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
155 }
156
TEST_F(InputDeviceMetricsCollectorTest,DontLogUsageForIgnoredDevices)157 TEST_F(InputDeviceMetricsCollectorTest, DontLogUsageForIgnoredDevices) {
158 constexpr static std::array<int32_t, 2> ignoredDevices{
159 {INVALID_INPUT_DEVICE_ID, VIRTUAL_KEYBOARD_ID}};
160
161 for (int32_t ignoredDeviceId : ignoredDevices) {
162 mMetricsCollector.notifyInputDevicesChanged(
163 {/*id=*/0, {generateTestDeviceInfo(ignoredDeviceId)}});
164
165 // Device was used.
166 mMetricsCollector.notifyMotion(generateMotionArgs(ignoredDeviceId));
167 mTestListener.assertNotifyMotionWasCalled();
168 mMetricsCollector.notifyDeviceInteraction(ignoredDeviceId, TIME.count(), uids({0, 1, 2}));
169 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
170
171 // Device was used again after the usage timeout expired, but we still don't log usage.
172 setCurrentTime(TIME + USAGE_TIMEOUT);
173 mMetricsCollector.notifyMotion(generateMotionArgs(ignoredDeviceId));
174 mTestListener.assertNotifyMotionWasCalled();
175 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
176
177 // Remove the ignored device, and ensure we still don't log usage.
178 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {}});
179 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
180 }
181 }
182
TEST_F(InputDeviceMetricsCollectorTest,LogsSingleEventUsageSession)183 TEST_F(InputDeviceMetricsCollectorTest, LogsSingleEventUsageSession) {
184 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
185
186 // Device was used.
187 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
188 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
189
190 // Device was used again after the usage timeout.
191 setCurrentTime(TIME + USAGE_TIMEOUT);
192 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
193 // The usage session has zero duration because it consisted of only one event.
194 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 0ns));
195 }
196
TEST_F(InputDeviceMetricsCollectorTest,LogsMultipleEventUsageSession)197 TEST_F(InputDeviceMetricsCollectorTest, LogsMultipleEventUsageSession) {
198 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
199
200 // Device was used.
201 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
202 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
203
204 // Device was used again after some time.
205 setCurrentTime(TIME + 21ns);
206 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
207
208 setCurrentTime(TIME + 42ns);
209 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
210
211 // Device was used again after the usage timeout.
212 setCurrentTime(TIME + 42ns + 2 * USAGE_TIMEOUT);
213 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
214 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 42ns));
215 }
216
TEST_F(InputDeviceMetricsCollectorTest,RemovingDeviceEndsUsageSession)217 TEST_F(InputDeviceMetricsCollectorTest, RemovingDeviceEndsUsageSession) {
218 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
219
220 // Device was used.
221 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
222 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
223
224 // Device was used again after some time.
225 setCurrentTime(TIME + 21ns);
226 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
227
228 // The device was removed before the usage timeout expired.
229 setCurrentTime(TIME + 42ns);
230 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {}});
231 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 21ns));
232 }
233
TEST_F(InputDeviceMetricsCollectorTest,TracksUsageFromDifferentDevicesIndependently)234 TEST_F(InputDeviceMetricsCollectorTest, TracksUsageFromDifferentDevicesIndependently) {
235 mMetricsCollector.notifyInputDevicesChanged(
236 {/*id=*/0, {TOUCHSCREEN_STYLUS_INFO, SECOND_TOUCHSCREEN_STYLUS_INFO}});
237
238 // Device 1 was used.
239 setCurrentTime(TIME);
240 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
241 setCurrentTime(TIME + 100ns);
242 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
243 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
244
245 // Device 2 was used.
246 setCurrentTime(TIME + 200ns);
247 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2));
248 setCurrentTime(TIME + 400ns);
249 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2));
250 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
251
252 // Device 1 was used after its usage timeout expired. Its usage session is reported.
253 setCurrentTime(TIME + 300ns + USAGE_TIMEOUT);
254 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
255 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 100ns));
256
257 // Device 2 was used.
258 setCurrentTime(TIME + 350ns + USAGE_TIMEOUT);
259 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2));
260 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
261
262 // Device 1 was used.
263 setCurrentTime(TIME + 500ns + USAGE_TIMEOUT);
264 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
265 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
266
267 // Device 2 is not used for a while, but Device 1 is used again.
268 setCurrentTime(TIME + 400ns + (2 * USAGE_TIMEOUT));
269 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
270 // Since Device 2's usage session ended, its usage should be reported.
271 ASSERT_NO_FATAL_FAILURE(
272 assertUsageLogged(SECOND_TOUCHSCREEN_STYLUS_INFO, 150ns + USAGE_TIMEOUT));
273
274 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
275 }
276
TEST_F(InputDeviceMetricsCollectorTest,BreakdownUsageBySource)277 TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageBySource) {
278 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
279 InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown;
280
281 // Use touchscreen.
282 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN));
283 setCurrentTime(TIME + 100ns);
284 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN));
285 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
286
287 // Use a stylus with the same input device.
288 setCurrentTime(TIME + 200ns);
289 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, STYLUS, {ToolType::STYLUS}));
290 setCurrentTime(TIME + 400ns);
291 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, STYLUS, {ToolType::STYLUS}));
292 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
293
294 // Touchscreen was used again after its usage timeout expired.
295 // This should be tracked as a separate usage of the source in the breakdown.
296 setCurrentTime(TIME + 300ns + USAGE_TIMEOUT);
297 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
298 expectedSourceBreakdown.emplace_back(InputDeviceUsageSource::TOUCHSCREEN, 100ns);
299 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
300
301 // Continue stylus and touchscreen usages.
302 setCurrentTime(TIME + 350ns + USAGE_TIMEOUT);
303 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, STYLUS, {ToolType::STYLUS}));
304 setCurrentTime(TIME + 450ns + USAGE_TIMEOUT);
305 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN));
306 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
307
308 // Touchscreen was used after the stylus's usage timeout expired.
309 // The stylus usage should be tracked in the source breakdown.
310 setCurrentTime(TIME + 400ns + USAGE_TIMEOUT + USAGE_TIMEOUT);
311 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN));
312 expectedSourceBreakdown.emplace_back(InputDeviceUsageSource::STYLUS_DIRECT,
313 150ns + USAGE_TIMEOUT);
314 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
315
316 // Remove all devices to force the usage session to be logged.
317 setCurrentTime(TIME + 500ns + USAGE_TIMEOUT);
318 mMetricsCollector.notifyInputDevicesChanged({});
319 expectedSourceBreakdown.emplace_back(InputDeviceUsageSource::TOUCHSCREEN,
320 100ns + USAGE_TIMEOUT);
321 // Verify that only one usage session was logged for the device, and that session was broken
322 // down by source correctly.
323 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO,
324 400ns + USAGE_TIMEOUT + USAGE_TIMEOUT,
325 expectedSourceBreakdown));
326
327 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
328 }
329
TEST_F(InputDeviceMetricsCollectorTest,BreakdownUsageBySource_TrackSourceByDevice)330 TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageBySource_TrackSourceByDevice) {
331 mMetricsCollector.notifyInputDevicesChanged(
332 {/*id=*/0, {TOUCHSCREEN_STYLUS_INFO, SECOND_TOUCHSCREEN_STYLUS_INFO}});
333 InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown1;
334 InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown2;
335
336 // Use both devices, with different sources.
337 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN));
338 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2, STYLUS, {ToolType::STYLUS}));
339 setCurrentTime(TIME + 100ns);
340 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN));
341 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2, STYLUS, {ToolType::STYLUS}));
342 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
343
344 // Remove all devices to force the usage session to be logged.
345 mMetricsCollector.notifyInputDevicesChanged({});
346 expectedSourceBreakdown1.emplace_back(InputDeviceUsageSource::TOUCHSCREEN, 100ns);
347 expectedSourceBreakdown2.emplace_back(InputDeviceUsageSource::STYLUS_DIRECT, 100ns);
348 ASSERT_NO_FATAL_FAILURE(
349 assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 100ns, expectedSourceBreakdown1));
350 ASSERT_NO_FATAL_FAILURE(
351 assertUsageLogged(SECOND_TOUCHSCREEN_STYLUS_INFO, 100ns, expectedSourceBreakdown2));
352
353 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
354 }
355
TEST_F(InputDeviceMetricsCollectorTest,BreakdownUsageBySource_MultiSourceEvent)356 TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageBySource_MultiSourceEvent) {
357 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
358 InputDeviceMetricsLogger::SourceUsageBreakdown expectedSourceBreakdown;
359
360 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN | STYLUS, //
361 {ToolType::STYLUS}));
362 setCurrentTime(TIME + 100ns);
363 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN | STYLUS, //
364 {ToolType::STYLUS, ToolType::FINGER}));
365 setCurrentTime(TIME + 200ns);
366 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN | STYLUS, //
367 {ToolType::STYLUS, ToolType::FINGER}));
368 setCurrentTime(TIME + 300ns);
369 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN | STYLUS, //
370 {ToolType::FINGER}));
371 setCurrentTime(TIME + 400ns);
372 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID, TOUCHSCREEN | STYLUS, //
373 {ToolType::FINGER}));
374 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
375
376 // Remove all devices to force the usage session to be logged.
377 mMetricsCollector.notifyInputDevicesChanged({});
378 expectedSourceBreakdown.emplace_back(InputDeviceUsageSource::STYLUS_DIRECT, 200ns);
379 expectedSourceBreakdown.emplace_back(InputDeviceUsageSource::TOUCHSCREEN, 300ns);
380 ASSERT_NO_FATAL_FAILURE(
381 assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 400ns, expectedSourceBreakdown));
382
383 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
384 }
385
TEST_F(InputDeviceMetricsCollectorTest,UidsNotTrackedWhenThereIsNoActiveSession)386 TEST_F(InputDeviceMetricsCollectorTest, UidsNotTrackedWhenThereIsNoActiveSession) {
387 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
388
389 // Notify interaction with UIDs before the device is used.
390 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1}));
391
392 // Use the device.
393 setCurrentTime(TIME + 100ns);
394 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
395 setCurrentTime(TIME + 200ns);
396 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
397
398 // Notify interaction for the wrong device.
399 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), uids({42}));
400
401 // Notify interaction after usage session would have expired.
402 // This interaction should not be tracked.
403 setCurrentTime(TIME + 200ns + USAGE_TIMEOUT);
404 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({2, 3}));
405
406 // Use the device again, by starting a new usage session.
407 setCurrentTime(TIME + 300ns + USAGE_TIMEOUT);
408 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
409
410 // The first usage session is logged.
411 static const UidUsageBreakdown emptyBreakdown;
412 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 100ns,
413 /*sourceBreakdown=*/{},
414 /*uidBreakdown=*/emptyBreakdown));
415
416 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
417 }
418
TEST_F(InputDeviceMetricsCollectorTest,BreakdownUsageByUid)419 TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageByUid) {
420 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
421 UidUsageBreakdown expectedUidBreakdown;
422
423 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
424 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1}));
425
426 setCurrentTime(TIME + 100ns);
427 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
428 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
429 setCurrentTime(TIME + 200ns);
430 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
431 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2, 3}));
432
433 expectedUidBreakdown.emplace_back(1, 200ns);
434 expectedUidBreakdown.emplace_back(2, 100ns);
435 expectedUidBreakdown.emplace_back(3, 0ns);
436
437 // Remove the device to force the usage session to be logged.
438 mMetricsCollector.notifyInputDevicesChanged({});
439 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 200ns,
440 /*sourceBreakdown=*/{}, expectedUidBreakdown));
441
442 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
443 }
444
TEST_F(InputDeviceMetricsCollectorTest,BreakdownUsageByUid_TracksMultipleSessionsForUid)445 TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageByUid_TracksMultipleSessionsForUid) {
446 mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {TOUCHSCREEN_STYLUS_INFO}});
447 UidUsageBreakdown expectedUidBreakdown;
448
449 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
450 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
451 setCurrentTime(TIME + 100ns);
452 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
453 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
454
455 setCurrentTime(TIME + 200ns);
456 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
457 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1}));
458
459 setCurrentTime(TIME + 300ns);
460 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
461 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 3}));
462 setCurrentTime(TIME + 400ns);
463 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
464 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 3}));
465
466 setCurrentTime(TIME + 200ns + USAGE_TIMEOUT);
467 expectedUidBreakdown.emplace_back(2, 100ns);
468 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
469 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({4}));
470
471 setCurrentTime(TIME + 300ns + USAGE_TIMEOUT);
472 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
473 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 4}));
474
475 setCurrentTime(TIME + 400ns + USAGE_TIMEOUT);
476 expectedUidBreakdown.emplace_back(3, 100ns);
477 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
478 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({2, 3}));
479
480 setCurrentTime(TIME + 500ns + USAGE_TIMEOUT);
481 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
482 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({3}));
483
484 // Remove the device to force the usage session to be logged.
485 mMetricsCollector.notifyInputDevicesChanged({});
486 expectedUidBreakdown.emplace_back(1, 300ns + USAGE_TIMEOUT);
487 expectedUidBreakdown.emplace_back(2, 0ns);
488 expectedUidBreakdown.emplace_back(3, 100ns);
489 expectedUidBreakdown.emplace_back(4, 100ns);
490 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 500ns + USAGE_TIMEOUT,
491 /*sourceBreakdown=*/{}, expectedUidBreakdown));
492
493 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
494 }
495
TEST_F(InputDeviceMetricsCollectorTest,BreakdownUsageByUid_TracksUidsByDevice)496 TEST_F(InputDeviceMetricsCollectorTest, BreakdownUsageByUid_TracksUidsByDevice) {
497 mMetricsCollector.notifyInputDevicesChanged(
498 {/*id=*/0, {TOUCHSCREEN_STYLUS_INFO, SECOND_TOUCHSCREEN_STYLUS_INFO}});
499 UidUsageBreakdown expectedUidBreakdown1;
500 UidUsageBreakdown expectedUidBreakdown2;
501
502 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
503 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
504
505 setCurrentTime(TIME + 100ns);
506 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2));
507 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), uids({1, 3}));
508
509 setCurrentTime(TIME + 200ns);
510 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
511 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
512 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2));
513 mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), uids({1, 3}));
514
515 setCurrentTime(TIME + 200ns + USAGE_TIMEOUT);
516 expectedUidBreakdown1.emplace_back(1, 200ns);
517 expectedUidBreakdown1.emplace_back(2, 200ns);
518 expectedUidBreakdown2.emplace_back(1, 100ns);
519 expectedUidBreakdown2.emplace_back(3, 100ns);
520 mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
521 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(TOUCHSCREEN_STYLUS_INFO, 200ns,
522 /*sourceBreakdown=*/{}, expectedUidBreakdown1));
523 ASSERT_NO_FATAL_FAILURE(assertUsageLogged(SECOND_TOUCHSCREEN_STYLUS_INFO, 100ns,
524 /*sourceBreakdown=*/{}, expectedUidBreakdown2));
525
526 ASSERT_NO_FATAL_FAILURE(assertUsageNotLogged());
527 }
528
529 } // namespace android
530