1 /* 2 * Copyright (C) 2015 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.widget.espresso; 18 19 import org.hamcrest.Matcher; 20 21 import android.support.test.espresso.UiController; 22 import android.support.test.espresso.ViewAction; 23 import android.support.test.espresso.action.CoordinatesProvider; 24 import android.support.test.espresso.action.MotionEvents; 25 import android.support.test.espresso.action.MotionEvents.DownResultHolder; 26 import android.support.test.espresso.action.Press; 27 import android.support.test.espresso.action.Tapper; 28 import android.view.MotionEvent; 29 import android.view.View; 30 import android.view.ViewConfiguration; 31 32 /** 33 * ViewAction for performing an click on View by a mouse. 34 */ 35 public final class MouseClickAction implements ViewAction { 36 private final ViewClickAction mViewClickAction; 37 @MouseUiController.MouseButton 38 private final int mButton; 39 40 public enum CLICK implements Tapper { 41 TRIPLE { 42 @Override 43 public Tapper.Status sendTap(UiController uiController, float[] coordinates, 44 float[] precision) { 45 Tapper.Status stat = sendSingleTap(uiController, coordinates, precision); 46 boolean warning = false; 47 if (stat == Tapper.Status.FAILURE) { 48 return Tapper.Status.FAILURE; 49 } else if (stat == Tapper.Status.WARNING) { 50 warning = true; 51 } 52 53 long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime(); 54 for (int i = 0; i < 2; i++) { 55 if (0 < doubleTapMinimumTimeout) { 56 uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout); 57 } 58 stat = sendSingleTap(uiController, coordinates, precision); 59 if (stat == Tapper.Status.FAILURE) { 60 return Tapper.Status.FAILURE; 61 } else if (stat == Tapper.Status.WARNING) { 62 warning = true; 63 } 64 } 65 66 if (warning) { 67 return Tapper.Status.WARNING; 68 } else { 69 return Tapper.Status.SUCCESS; 70 } 71 } 72 }; 73 74 private static Tapper.Status sendSingleTap(UiController uiController, 75 float[] coordinates, float[] precision) { 76 DownResultHolder res = MotionEvents.sendDown(uiController, coordinates, precision); 77 try { 78 if (!MotionEvents.sendUp(uiController, res.down)) { 79 MotionEvents.sendCancel(uiController, res.down); 80 return Tapper.Status.FAILURE; 81 } 82 } finally { 83 res.down.recycle(); 84 } 85 return res.longPress ? Tapper.Status.WARNING : Tapper.Status.SUCCESS; 86 } 87 }; 88 89 public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider) { 90 this(tapper, coordinatesProvider, MotionEvent.BUTTON_PRIMARY); 91 } 92 93 /** 94 * Constructs MouseClickAction 95 * 96 * @param tapper the tapper 97 * @param coordinatesProvider the provider of the event coordinates 98 * @param button the mouse button used to send motion events 99 */ 100 public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider, 101 @MouseUiController.MouseButton int button) { 102 mViewClickAction = new ViewClickAction(tapper, coordinatesProvider, Press.PINPOINT); 103 mButton = button; 104 } 105 106 @Override 107 public Matcher<View> getConstraints() { 108 return mViewClickAction.getConstraints(); 109 } 110 111 @Override 112 public String getDescription() { 113 return mViewClickAction.getDescription(); 114 } 115 116 @Override 117 public void perform(UiController uiController, View view) { 118 mViewClickAction.perform(new MouseUiController(uiController, mButton), view); 119 } 120 } 121