1 /*
2  * Copyright (C) 2018 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.textclassifier.common.statsd;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.view.textclassifier.SelectionEvent;
22 import android.view.textclassifier.TextClassification;
23 import android.view.textclassifier.TextClassificationContext;
24 import android.view.textclassifier.TextClassificationManager;
25 import android.view.textclassifier.TextClassifier;
26 import android.view.textclassifier.TextClassifierEvent;
27 import android.view.textclassifier.TextSelection;
28 import androidx.test.core.app.ApplicationProvider;
29 import androidx.test.ext.junit.runners.AndroidJUnit4;
30 import androidx.test.filters.SmallTest;
31 import com.android.textclassifier.common.logging.ResultIdUtils;
32 import com.android.textclassifier.common.logging.ResultIdUtils.ModelInfo;
33 import com.google.common.base.Optional;
34 import com.google.common.collect.ImmutableList;
35 import java.util.ArrayDeque;
36 import java.util.Deque;
37 import java.util.Locale;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 @SmallTest
43 @RunWith(AndroidJUnit4.class)
44 public class SelectionEventConverterTest {
45   private static final String PKG_NAME = "com.pkg";
46   private static final String WIDGET_TYPE = TextClassifier.WIDGET_TYPE_EDITTEXT;
47   private static final int START = 2;
48   private static final int SMART_START = 1;
49   private static final int SMART_END = 3;
50   private TestTextClassifier testTextClassifier;
51   private TextClassifier session;
52 
53   @Before
setup()54   public void setup() {
55     TextClassificationManager textClassificationManager =
56         ApplicationProvider.getApplicationContext()
57             .getSystemService(TextClassificationManager.class);
58     testTextClassifier = new TestTextClassifier();
59     textClassificationManager.setTextClassifier(testTextClassifier);
60     session = textClassificationManager.createTextClassificationSession(createEventContext());
61   }
62 
63   @Test
convert_started()64   public void convert_started() {
65     session.onSelectionEvent(
66         SelectionEvent.createSelectionStartedEvent(SelectionEvent.INVOCATION_MANUAL, START));
67 
68     SelectionEvent interceptedEvent = testTextClassifier.popLastSelectionEvent();
69     TextClassifierEvent textClassifierEvent =
70         SelectionEventConverter.toTextClassifierEvent(interceptedEvent);
71 
72     assertEventContext(textClassifierEvent.getEventContext());
73     assertThat(textClassifierEvent.getEventIndex()).isEqualTo(0);
74     assertThat(textClassifierEvent.getEventType())
75         .isEqualTo(TextClassifierEvent.TYPE_SELECTION_STARTED);
76   }
77 
78   @Test
convert_smartSelection()79   public void convert_smartSelection() {
80     session.onSelectionEvent(
81         SelectionEvent.createSelectionStartedEvent(SelectionEvent.INVOCATION_MANUAL, START));
82     String resultId = createResultId();
83     session.onSelectionEvent(
84         SelectionEvent.createSelectionActionEvent(
85             SMART_START,
86             SMART_END,
87             SelectionEvent.ACTION_SMART_SHARE,
88             new TextClassification.Builder()
89                 .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
90                 .setId(resultId)
91                 .build()));
92 
93     SelectionEvent interceptedEvent = testTextClassifier.popLastSelectionEvent();
94     TextClassifierEvent.TextSelectionEvent textSelectionEvent =
95         (TextClassifierEvent.TextSelectionEvent)
96             SelectionEventConverter.toTextClassifierEvent(interceptedEvent);
97 
98     assertEventContext(textSelectionEvent.getEventContext());
99     assertThat(textSelectionEvent.getRelativeWordStartIndex()).isEqualTo(-1);
100     assertThat(textSelectionEvent.getRelativeWordEndIndex()).isEqualTo(1);
101     assertThat(textSelectionEvent.getEventType()).isEqualTo(TextClassifierEvent.TYPE_SMART_ACTION);
102     assertThat(textSelectionEvent.getEventIndex()).isEqualTo(1);
103     assertThat(textSelectionEvent.getEntityTypes())
104         .asList()
105         .containsExactly(TextClassifier.TYPE_ADDRESS);
106     assertThat(textSelectionEvent.getResultId()).isEqualTo(resultId);
107   }
108 
109   @Test
convert_smartShare()110   public void convert_smartShare() {
111     session.onSelectionEvent(
112         SelectionEvent.createSelectionStartedEvent(SelectionEvent.INVOCATION_MANUAL, START));
113     String resultId = createResultId();
114     session.onSelectionEvent(
115         SelectionEvent.createSelectionModifiedEvent(
116             SMART_START,
117             SMART_END,
118             new TextSelection.Builder(SMART_START, SMART_END)
119                 .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
120                 .setId(resultId)
121                 .build()));
122 
123     SelectionEvent interceptedEvent = testTextClassifier.popLastSelectionEvent();
124     TextClassifierEvent.TextSelectionEvent textSelectionEvent =
125         (TextClassifierEvent.TextSelectionEvent)
126             SelectionEventConverter.toTextClassifierEvent(interceptedEvent);
127 
128     assertEventContext(textSelectionEvent.getEventContext());
129     assertThat(textSelectionEvent.getRelativeSuggestedWordStartIndex()).isEqualTo(-1);
130     assertThat(textSelectionEvent.getRelativeSuggestedWordEndIndex()).isEqualTo(1);
131     assertThat(textSelectionEvent.getEventType())
132         .isEqualTo(TextClassifierEvent.TYPE_SMART_SELECTION_MULTI);
133     assertThat(textSelectionEvent.getEventIndex()).isEqualTo(1);
134     assertThat(textSelectionEvent.getEntityTypes())
135         .asList()
136         .containsExactly(TextClassifier.TYPE_ADDRESS);
137     assertThat(textSelectionEvent.getResultId()).isEqualTo(resultId);
138   }
139 
140   @Test
convert_smartLinkify()141   public void convert_smartLinkify() {
142     session.onSelectionEvent(
143         SelectionEvent.createSelectionStartedEvent(SelectionEvent.INVOCATION_LINK, START));
144     String resultId = createResultId();
145     session.onSelectionEvent(
146         SelectionEvent.createSelectionModifiedEvent(
147             SMART_START,
148             SMART_END,
149             new TextSelection.Builder(SMART_START, SMART_END)
150                 .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
151                 .setId(resultId)
152                 .build()));
153 
154     SelectionEvent interceptedEvent = testTextClassifier.popLastSelectionEvent();
155     TextClassifierEvent.TextLinkifyEvent textLinkifyEvent =
156         (TextClassifierEvent.TextLinkifyEvent)
157             SelectionEventConverter.toTextClassifierEvent(interceptedEvent);
158 
159     assertEventContext(textLinkifyEvent.getEventContext());
160     assertThat(textLinkifyEvent.getEventType())
161         .isEqualTo(TextClassifierEvent.TYPE_SMART_SELECTION_MULTI);
162     assertThat(textLinkifyEvent.getEventIndex()).isEqualTo(1);
163     assertThat(textLinkifyEvent.getEntityTypes())
164         .asList()
165         .containsExactly(TextClassifier.TYPE_ADDRESS);
166     assertThat(textLinkifyEvent.getResultId()).isEqualTo(resultId);
167   }
168 
createEventContext()169   private static TextClassificationContext createEventContext() {
170     return new TextClassificationContext.Builder(PKG_NAME, TextClassifier.WIDGET_TYPE_EDITTEXT)
171         .build();
172   }
173 
assertEventContext(TextClassificationContext eventContext)174   private static void assertEventContext(TextClassificationContext eventContext) {
175     assertThat(eventContext.getPackageName()).isEqualTo(PKG_NAME);
176     assertThat(eventContext.getWidgetType()).isEqualTo(WIDGET_TYPE);
177   }
178 
createResultId()179   private static String createResultId() {
180     return ResultIdUtils.createId(
181         /*hash=*/ 12345,
182         ImmutableList.of(
183             Optional.of(new ModelInfo(/* version= */ 702, ImmutableList.of(Locale.ENGLISH)))));
184   }
185 
186   private static class TestTextClassifier implements TextClassifier {
187     private final Deque<SelectionEvent> selectionEvents = new ArrayDeque<>();
188 
189     @Override
onSelectionEvent(SelectionEvent event)190     public void onSelectionEvent(SelectionEvent event) {
191       selectionEvents.push(event);
192     }
193 
popLastSelectionEvent()194     SelectionEvent popLastSelectionEvent() {
195       return selectionEvents.pop();
196     }
197   }
198 }
199