• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 package com.android.intentresolver.logging;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.AdditionalMatchers.gt;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyBoolean;
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.ArgumentMatchers.isNull;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.verifyNoMoreInteractions;
31 
32 import android.content.Intent;
33 import android.metrics.LogMaker;
34 
35 import com.android.intentresolver.contentpreview.ContentPreviewType;
36 import com.android.intentresolver.logging.EventLogImpl.SharesheetStandardEvent;
37 import com.android.intentresolver.logging.EventLogImpl.SharesheetStartedEvent;
38 import com.android.intentresolver.logging.EventLogImpl.SharesheetTargetSelectedEvent;
39 import com.android.internal.logging.InstanceId;
40 import com.android.internal.logging.InstanceIdSequence;
41 import com.android.internal.logging.MetricsLogger;
42 import com.android.internal.logging.UiEventLogger;
43 import com.android.internal.logging.UiEventLogger.UiEventEnum;
44 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
45 import com.android.internal.util.FrameworkStatsLog;
46 
47 import org.junit.After;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.ArgumentCaptor;
52 import org.mockito.Mock;
53 import org.mockito.junit.MockitoJUnitRunner;
54 
55 @RunWith(MockitoJUnitRunner.class)
56 public final class EventLogImplTest {
57     @Mock private UiEventLogger mUiEventLog;
58     @Mock private FrameworkStatsLogger mFrameworkLog;
59     @Mock private MetricsLogger mMetricsLogger;
60 
61     private EventLogImpl mChooserLogger;
62 
63     private final InstanceIdSequence mSequence = EventLogImpl.newIdSequence();
64 
65     @Before
setUp()66     public void setUp() {
67         mChooserLogger = new EventLogImpl(mUiEventLog, mFrameworkLog, mMetricsLogger,
68                 mSequence.newInstanceId());
69     }
70 
71     @After
tearDown()72     public void tearDown() {
73         verifyNoMoreInteractions(mUiEventLog);
74         verifyNoMoreInteractions(mFrameworkLog);
75         verifyNoMoreInteractions(mMetricsLogger);
76     }
77 
78     @Test
testLogChooserActivityShown_personalProfile()79     public void testLogChooserActivityShown_personalProfile() {
80         final boolean isWorkProfile = false;
81         final String mimeType = "application/TestType";
82         final long systemCost = 456;
83 
84         mChooserLogger.logChooserActivityShown(isWorkProfile, mimeType, systemCost);
85 
86         ArgumentCaptor<LogMaker> eventCaptor = ArgumentCaptor.forClass(LogMaker.class);
87         verify(mMetricsLogger).write(eventCaptor.capture());
88         LogMaker event = eventCaptor.getValue();
89 
90         assertThat(event.getCategory()).isEqualTo(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN);
91         assertThat(event.getSubtype()).isEqualTo(MetricsEvent.PARENT_PROFILE);
92         assertThat(event.getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE)).isEqualTo(mimeType);
93         assertThat(event.getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS))
94                 .isEqualTo(systemCost);
95     }
96 
97     @Test
testLogChooserActivityShown_workProfile()98     public void testLogChooserActivityShown_workProfile() {
99         final boolean isWorkProfile = true;
100         final String mimeType = "application/TestType";
101         final long systemCost = 456;
102 
103         mChooserLogger.logChooserActivityShown(isWorkProfile, mimeType, systemCost);
104 
105         ArgumentCaptor<LogMaker> eventCaptor = ArgumentCaptor.forClass(LogMaker.class);
106         verify(mMetricsLogger).write(eventCaptor.capture());
107         LogMaker event = eventCaptor.getValue();
108 
109         assertThat(event.getCategory()).isEqualTo(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN);
110         assertThat(event.getSubtype()).isEqualTo(MetricsEvent.MANAGED_PROFILE);
111         assertThat(event.getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE)).isEqualTo(mimeType);
112         assertThat(event.getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS))
113                 .isEqualTo(systemCost);
114     }
115 
116     @Test
testLogShareStarted()117     public void testLogShareStarted() {
118         final String packageName = "com.test.foo";
119         final String mimeType = "text/plain";
120         final int appProvidedDirectTargets = 123;
121         final int appProvidedAppTargets = 456;
122         final boolean workProfile = true;
123         final int previewType = ContentPreviewType.CONTENT_PREVIEW_FILE;
124         final String intentAction = Intent.ACTION_SENDTO;
125         final int numCustomActions = 3;
126         final boolean modifyShareProvided = true;
127 
128         mChooserLogger.logShareStarted(
129                 packageName,
130                 mimeType,
131                 appProvidedDirectTargets,
132                 appProvidedAppTargets,
133                 workProfile,
134                 previewType,
135                 intentAction,
136                 numCustomActions,
137                 modifyShareProvided);
138 
139         verify(mFrameworkLog).write(
140                 eq(FrameworkStatsLog.SHARESHEET_STARTED),
141                 eq(SharesheetStartedEvent.SHARE_STARTED.getId()),
142                 eq(packageName),
143                 /* instanceId=*/ gt(0),
144                 eq(mimeType),
145                 eq(appProvidedDirectTargets),
146                 eq(appProvidedAppTargets),
147                 eq(workProfile),
148                 eq(FrameworkStatsLog.SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_FILE),
149                 eq(FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SENDTO),
150                 /* custom actions provided */ eq(numCustomActions),
151                 /* reselection action provided */ eq(modifyShareProvided));
152     }
153 
154     @Test
shareStartedWithShareouselAndEnabledReportingFlag_imagePreviewTypeReported()155     public void shareStartedWithShareouselAndEnabledReportingFlag_imagePreviewTypeReported() {
156         final String packageName = "com.test.foo";
157         final String mimeType = "text/plain";
158         final int appProvidedDirectTargets = 123;
159         final int appProvidedAppTargets = 456;
160         final boolean workProfile = true;
161         final int previewType = ContentPreviewType.CONTENT_PREVIEW_PAYLOAD_SELECTION;
162         final String intentAction = Intent.ACTION_SENDTO;
163         final int numCustomActions = 3;
164         final boolean modifyShareProvided = true;
165 
166         mChooserLogger.logShareStarted(
167                 packageName,
168                 mimeType,
169                 appProvidedDirectTargets,
170                 appProvidedAppTargets,
171                 workProfile,
172                 previewType,
173                 intentAction,
174                 numCustomActions,
175                 modifyShareProvided);
176 
177         verify(mFrameworkLog).write(
178                 eq(FrameworkStatsLog.SHARESHEET_STARTED),
179                 eq(SharesheetStartedEvent.SHARE_STARTED.getId()),
180                 eq(packageName),
181                 /* instanceId=*/ gt(0),
182                 eq(mimeType),
183                 eq(appProvidedDirectTargets),
184                 eq(appProvidedAppTargets),
185                 eq(workProfile),
186                 eq(FrameworkStatsLog
187                         .SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_TOGGLEABLE_MEDIA),
188                 eq(FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_SENDTO),
189                 /* custom actions provided */ eq(numCustomActions),
190                 /* reselection action provided */ eq(modifyShareProvided));
191     }
192 
193     @Test
testLogShareTargetSelected()194     public void testLogShareTargetSelected() {
195         final int targetType = EventLogImpl.SELECTION_TYPE_SERVICE;
196         final String packageName = "com.test.foo";
197         final int positionPicked = 123;
198         final int directTargetAlsoRanked = -1;
199         final int callerTargetCount = 0;
200         final boolean isPinned = true;
201         final boolean isSuccessfullySelected = true;
202         final long selectionCost = 456;
203 
204         mChooserLogger.logShareTargetSelected(
205                 targetType,
206                 packageName,
207                 positionPicked,
208                 directTargetAlsoRanked,
209                 callerTargetCount,
210                 /* directTargetHashed= */ null,
211                 isPinned,
212                 isSuccessfullySelected,
213                 selectionCost);
214 
215         verify(mFrameworkLog).write(
216                 eq(FrameworkStatsLog.RANKING_SELECTED),
217                 eq(SharesheetTargetSelectedEvent.SHARESHEET_SERVICE_TARGET_SELECTED.getId()),
218                 eq(packageName),
219                 /* instanceId=*/ gt(0),
220                 eq(positionPicked),
221                 eq(isPinned));
222 
223         ArgumentCaptor<LogMaker> eventCaptor = ArgumentCaptor.forClass(LogMaker.class);
224         verify(mMetricsLogger).write(eventCaptor.capture());
225         LogMaker event = eventCaptor.getValue();
226         assertThat(event.getCategory()).isEqualTo(
227                 MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET);
228         assertThat(event.getSubtype()).isEqualTo(positionPicked);
229     }
230 
231     @Test
testLogActionSelected()232     public void testLogActionSelected() {
233         mChooserLogger.logActionSelected(EventLogImpl.SELECTION_TYPE_COPY);
234 
235         verify(mFrameworkLog).write(
236                 eq(FrameworkStatsLog.RANKING_SELECTED),
237                 eq(SharesheetTargetSelectedEvent.SHARESHEET_COPY_TARGET_SELECTED.getId()),
238                 eq(""),
239                 /* instanceId=*/ gt(0),
240                 eq(-1),
241                 eq(false));
242 
243         ArgumentCaptor<LogMaker> eventCaptor = ArgumentCaptor.forClass(LogMaker.class);
244         verify(mMetricsLogger).write(eventCaptor.capture());
245         LogMaker event = eventCaptor.getValue();
246         assertThat(event.getCategory()).isEqualTo(
247                 MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SYSTEM_TARGET);
248         assertThat(event.getSubtype()).isEqualTo(1);
249     }
250 
251     @Test
testLogCustomActionSelected()252     public void testLogCustomActionSelected() {
253         final int position = 4;
254         mChooserLogger.logCustomActionSelected(position);
255 
256         verify(mFrameworkLog).write(
257                 eq(FrameworkStatsLog.RANKING_SELECTED),
258                 eq(SharesheetTargetSelectedEvent.SHARESHEET_CUSTOM_ACTION_SELECTED.getId()),
259                 any(), anyInt(), eq(position), eq(false));
260     }
261 
262     @Test
testLogDirectShareTargetReceived()263     public void testLogDirectShareTargetReceived() {
264         final int category = MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER;
265         final int latency = 123;
266 
267         mChooserLogger.logDirectShareTargetReceived(category, latency);
268 
269         ArgumentCaptor<LogMaker> eventCaptor = ArgumentCaptor.forClass(LogMaker.class);
270         verify(mMetricsLogger).write(eventCaptor.capture());
271         LogMaker event = eventCaptor.getValue();
272         assertThat(event.getCategory()).isEqualTo(category);
273         assertThat(event.getSubtype()).isEqualTo(latency);
274     }
275 
276     @Test
testLogActionShareWithPreview()277     public void testLogActionShareWithPreview() {
278         final int previewType = ContentPreviewType.CONTENT_PREVIEW_TEXT;
279 
280         mChooserLogger.logActionShareWithPreview(previewType);
281 
282         ArgumentCaptor<LogMaker> eventCaptor = ArgumentCaptor.forClass(LogMaker.class);
283         verify(mMetricsLogger).write(eventCaptor.capture());
284         LogMaker event = eventCaptor.getValue();
285         assertThat(event.getCategory()).isEqualTo(MetricsEvent.ACTION_SHARE_WITH_PREVIEW);
286         assertThat(event.getSubtype()).isEqualTo(previewType);
287     }
288 
289     @Test
testLogSharesheetTriggered()290     public void testLogSharesheetTriggered() {
291         mChooserLogger.logSharesheetTriggered();
292         verify(mUiEventLog).logWithInstanceId(
293                 eq(SharesheetStandardEvent.SHARESHEET_TRIGGERED), eq(0), isNull(), any());
294     }
295 
296     @Test
testLogSharesheetAppLoadComplete()297     public void testLogSharesheetAppLoadComplete() {
298         mChooserLogger.logSharesheetAppLoadComplete();
299         verify(mUiEventLog).logWithInstanceId(
300                 eq(SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE), eq(0), isNull(), any());
301     }
302 
303     @Test
testLogSharesheetDirectLoadComplete()304     public void testLogSharesheetDirectLoadComplete() {
305         mChooserLogger.logSharesheetDirectLoadComplete();
306         verify(mUiEventLog).logWithInstanceId(
307                 eq(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE),
308                 eq(0),
309                 isNull(),
310                 any());
311     }
312 
313     @Test
testLogSharesheetDirectLoadTimeout()314     public void testLogSharesheetDirectLoadTimeout() {
315         mChooserLogger.logSharesheetDirectLoadTimeout();
316         verify(mUiEventLog).logWithInstanceId(
317                 eq(SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_TIMEOUT), eq(0), isNull(), any());
318     }
319 
320     @Test
testLogSharesheetProfileChanged()321     public void testLogSharesheetProfileChanged() {
322         mChooserLogger.logSharesheetProfileChanged();
323         verify(mUiEventLog).logWithInstanceId(
324                 eq(SharesheetStandardEvent.SHARESHEET_PROFILE_CHANGED), eq(0), isNull(), any());
325     }
326 
327     @Test
testLogSharesheetExpansionChanged_collapsed()328     public void testLogSharesheetExpansionChanged_collapsed() {
329         mChooserLogger.logSharesheetExpansionChanged(/* isCollapsed=*/ true);
330         verify(mUiEventLog).logWithInstanceId(
331                 eq(SharesheetStandardEvent.SHARESHEET_COLLAPSED), eq(0), isNull(), any());
332     }
333 
334     @Test
testLogSharesheetExpansionChanged_expanded()335     public void testLogSharesheetExpansionChanged_expanded() {
336         mChooserLogger.logSharesheetExpansionChanged(/* isCollapsed=*/ false);
337         verify(mUiEventLog).logWithInstanceId(
338                 eq(SharesheetStandardEvent.SHARESHEET_EXPANDED), eq(0), isNull(), any());
339     }
340 
341     @Test
testLogSharesheetAppShareRankingTimeout()342     public void testLogSharesheetAppShareRankingTimeout() {
343         mChooserLogger.logSharesheetAppShareRankingTimeout();
344         verify(mUiEventLog).logWithInstanceId(
345                 eq(SharesheetStandardEvent.SHARESHEET_APP_SHARE_RANKING_TIMEOUT),
346                 eq(0),
347                 isNull(),
348                 any());
349     }
350 
351     @Test
testLogSharesheetEmptyDirectShareRow()352     public void testLogSharesheetEmptyDirectShareRow() {
353         mChooserLogger.logSharesheetEmptyDirectShareRow();
354         verify(mUiEventLog).logWithInstanceId(
355                 eq(SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW),
356                 eq(0),
357                 isNull(),
358                 any());
359     }
360 
361     @Test
testDifferentLoggerInstancesUseDifferentInstanceIds()362     public void testDifferentLoggerInstancesUseDifferentInstanceIds() {
363         ArgumentCaptor<Integer> idIntCaptor = ArgumentCaptor.forClass(Integer.class);
364         EventLogImpl chooserLogger2 =
365                 new EventLogImpl(mUiEventLog, mFrameworkLog, mMetricsLogger,
366                         mSequence.newInstanceId());
367 
368         final int targetType = EventLogImpl.SELECTION_TYPE_COPY;
369         final String packageName = "com.test.foo";
370         final int positionPicked = 123;
371         final int directTargetAlsoRanked = -1;
372         final int callerTargetCount = 0;
373         final boolean isPinned = true;
374         final boolean isSuccessfullySelected = true;
375         final long selectionCost = 456;
376 
377         mChooserLogger.logShareTargetSelected(
378                 targetType,
379                 packageName,
380                 positionPicked,
381                 directTargetAlsoRanked,
382                 callerTargetCount,
383                 /* directTargetHashed= */ null,
384                 isPinned,
385                 isSuccessfullySelected,
386                 selectionCost);
387 
388         chooserLogger2.logShareTargetSelected(
389                 targetType,
390                 packageName,
391                 positionPicked,
392                 directTargetAlsoRanked,
393                 callerTargetCount,
394                 /* directTargetHashed= */ null,
395                 isPinned,
396                 isSuccessfullySelected,
397                 selectionCost);
398 
399         verify(mFrameworkLog, times(2)).write(
400                 anyInt(), anyInt(), anyString(), idIntCaptor.capture(), anyInt(), anyBoolean());
401 
402         int id1 = idIntCaptor.getAllValues().get(0);
403         int id2 = idIntCaptor.getAllValues().get(1);
404 
405         assertThat(id1).isGreaterThan(0);
406         assertThat(id2).isGreaterThan(0);
407         assertThat(id1).isNotEqualTo(id2);
408     }
409 
410     @Test
testUiAndFrameworkEventsUseSameInstanceIdForSameLoggerInstance()411     public void testUiAndFrameworkEventsUseSameInstanceIdForSameLoggerInstance() {
412         ArgumentCaptor<Integer> idIntCaptor = ArgumentCaptor.forClass(Integer.class);
413         ArgumentCaptor<InstanceId> idObjectCaptor = ArgumentCaptor.forClass(InstanceId.class);
414 
415         final int targetType = EventLogImpl.SELECTION_TYPE_COPY;
416         final String packageName = "com.test.foo";
417         final int positionPicked = 123;
418         final int directTargetAlsoRanked = -1;
419         final int callerTargetCount = 0;
420         final boolean isPinned = true;
421         final boolean isSuccessfullySelected = true;
422         final long selectionCost = 456;
423 
424         mChooserLogger.logShareTargetSelected(
425                 targetType,
426                 packageName,
427                 positionPicked,
428                 directTargetAlsoRanked,
429                 callerTargetCount,
430                 /* directTargetHashed= */ null,
431                 isPinned,
432                 isSuccessfullySelected,
433                 selectionCost);
434 
435         verify(mFrameworkLog).write(
436                 anyInt(), anyInt(), anyString(), idIntCaptor.capture(), anyInt(), anyBoolean());
437 
438         mChooserLogger.logSharesheetTriggered();
439         verify(mUiEventLog).logWithInstanceId(
440                 any(UiEventEnum.class), anyInt(), any(), idObjectCaptor.capture());
441 
442         assertThat(idIntCaptor.getValue()).isGreaterThan(0);
443         assertThat(idObjectCaptor.getValue().getId()).isEqualTo(idIntCaptor.getValue());
444     }
445 
446     @Test
testTargetSelectionCategories()447     public void testTargetSelectionCategories() {
448         assertThat(EventLogImpl.getTargetSelectionCategory(
449                 EventLogImpl.SELECTION_TYPE_SERVICE))
450                         .isEqualTo(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET);
451         assertThat(EventLogImpl.getTargetSelectionCategory(
452                 EventLogImpl.SELECTION_TYPE_APP))
453                         .isEqualTo(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET);
454         assertThat(EventLogImpl.getTargetSelectionCategory(
455                 EventLogImpl.SELECTION_TYPE_STANDARD))
456                         .isEqualTo(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET);
457         assertThat(EventLogImpl.getTargetSelectionCategory(
458                 EventLogImpl.SELECTION_TYPE_COPY)).isEqualTo(0);
459         assertThat(EventLogImpl.getTargetSelectionCategory(
460                 EventLogImpl.SELECTION_TYPE_NEARBY)).isEqualTo(0);
461         assertThat(EventLogImpl.getTargetSelectionCategory(
462                 EventLogImpl.SELECTION_TYPE_EDIT)).isEqualTo(0);
463     }
464 }
465