1 /*
2  * Copyright (C) 2020 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 android.view.textclassifier.cts;
18 
19 import static androidx.test.espresso.action.ViewActions.actionWithAssertions;
20 
21 import android.text.Layout;
22 import android.util.Log;
23 import android.view.View;
24 import android.widget.TextView;
25 
26 import androidx.test.espresso.UiController;
27 import androidx.test.espresso.ViewAction;
28 import androidx.test.espresso.action.CoordinatesProvider;
29 import androidx.test.espresso.action.GeneralClickAction;
30 import androidx.test.espresso.action.PrecisionDescriber;
31 import androidx.test.espresso.action.Press;
32 import androidx.test.espresso.action.Tap;
33 import androidx.test.espresso.action.Tapper;
34 
35 import org.hamcrest.Matcher;
36 
37 import java.util.Arrays;
38 
39 /**
40  * Espresso utils to perform actions on a TextView.
41  */
42 public final class TextViewActions {
43     private static final String TAG = "TextViewActions";
44 
45     /**
46      * Tap on the text at the given character index.
47      */
tapOnTextAtIndex(int index)48     public static ViewAction tapOnTextAtIndex(int index) {
49         return actionWithAssertions(
50                 new ViewClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
51     }
52 
longTapOnTextAtIndex(int index)53     public static ViewAction longTapOnTextAtIndex(int index) {
54         return actionWithAssertions(
55                 new ViewClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
56     }
57 
58     private static final class ViewClickAction implements ViewAction {
59         private final GeneralClickAction mGeneralClickAction;
60 
ViewClickAction( Tapper tapper, CoordinatesProvider coordinatesProvider, PrecisionDescriber precisionDescriber)61         public ViewClickAction(
62                 Tapper tapper,
63                 CoordinatesProvider coordinatesProvider,
64                 PrecisionDescriber precisionDescriber) {
65             mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
66                     precisionDescriber);
67         }
68 
69         @Override
getConstraints()70         public Matcher<View> getConstraints() {
71             return mGeneralClickAction.getConstraints();
72         }
73 
74         @Override
getDescription()75         public String getDescription() {
76             return mGeneralClickAction.getDescription();
77         }
78 
79         @Override
perform(UiController uiController, View view)80         public void perform(UiController uiController, View view) {
81             mGeneralClickAction.perform(uiController, view);
82         }
83     }
84 
85     private static final class TextCoordinates implements CoordinatesProvider {
86 
87         private final int mIndex;
88 
TextCoordinates(int index)89         public TextCoordinates(int index) {
90             mIndex = index;
91         }
92 
93         @Override
calculateCoordinates(View view)94         public float[] calculateCoordinates(View view) {
95             TextView textView = (TextView) view;
96             final Layout layout = textView.getLayout();
97             final int line = layout.getLineForOffset(mIndex);
98             final int[] xy = new int[2];
99             textView.getLocationOnScreen(xy);
100             float[] coordinates = new float[]{
101                     layout.getPrimaryHorizontal(mIndex)
102                             + textView.getTotalPaddingLeft()
103                             - textView.getScrollX()
104                             + xy[0],
105                     layout.getLineTop(line) + textView.getTotalPaddingTop() - textView.getScrollY()
106                             + xy[1]};
107             Log.d(TAG, "calculateCoordinates: " + Arrays.toString(coordinates));
108             return coordinates;
109         }
110     }
111 
TextViewActions()112     private TextViewActions() {
113     }
114 }