• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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