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 }