• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.annotation.IntDef;
22 import android.os.SystemClock;
23 import android.view.InputDevice;
24 import android.view.KeyEvent;
25 import android.view.MotionEvent;
26 
27 import androidx.test.espresso.InjectEventSecurityException;
28 import androidx.test.espresso.UiController;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.util.Iterator;
33 
34 /**
35  * Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE.
36  * Note that this doesn't change the tool type.
37  */
38 public final class MouseUiController implements UiController {
39     @Retention(RetentionPolicy.SOURCE)
40     @IntDef({MotionEvent.BUTTON_PRIMARY, MotionEvent.BUTTON_SECONDARY, MotionEvent.BUTTON_TERTIARY})
41     public @interface MouseButton {}
42 
43     private final UiController mUiController;
44     @MouseButton
45     private final int mButton;
46 
MouseUiController(UiController uiController)47     public MouseUiController(UiController uiController) {
48         this(uiController, MotionEvent.BUTTON_PRIMARY);
49     }
50 
51     /**
52      * Constructs MouseUiController.
53      *
54      * @param uiController the uiController to wrap
55      * @param button the button to be used for generating input events.
56      */
MouseUiController(UiController uiController, @MouseButton int button)57     public MouseUiController(UiController uiController, @MouseButton int button) {
58         mUiController = checkNotNull(uiController);
59         mButton = button;
60     }
61 
62     @Override
injectKeyEvent(KeyEvent event)63     public boolean injectKeyEvent(KeyEvent event) throws InjectEventSecurityException {
64         return mUiController.injectKeyEvent(event);
65     }
66 
67     @Override
injectMotionEvent(MotionEvent event)68     public boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException {
69         // Modify the event to mimic mouse event.
70         event.setSource(InputDevice.SOURCE_MOUSE);
71         if (event.getActionMasked() != MotionEvent.ACTION_UP) {
72             event.setButtonState(mButton);
73         }
74         return mUiController.injectMotionEvent(event);
75     }
76 
77     /**
78      * Copied from latest {@link androidx.test.espresso.UiController}, since current
79      * {@link androidx.test.espresso.UiController#injectMotionEventSequence(Iterable)} seems not a
80      * default method.
81      */
82     @Override
injectMotionEventSequence(Iterable<MotionEvent> events)83     public boolean injectMotionEventSequence(Iterable<MotionEvent> events)
84             throws InjectEventSecurityException {
85         android.util.Log.w(
86                 "UIC",
87                 "Using default injectMotionEventSeq() - this may not inject a sequence properly. "
88                 + "If wrapping UIController please override this method and delegate.");
89         Iterator<MotionEvent> mei = events.iterator();
90         boolean success = true;
91         while (mei.hasNext()) {
92             MotionEvent me = mei.next();
93             if (me.getEventTime() - SystemClock.uptimeMillis() > 10) {
94                 // Because the loopMainThreadForAtLeast is overkill for waiting, intentially only
95                 // call it with a smaller amount of milliseconds as best effort
96                 loopMainThreadForAtLeast(10);
97             }
98             success &= injectMotionEvent(me);
99         }
100         return success;
101     }
102 
103     @Override
injectString(String str)104     public boolean injectString(String str) throws InjectEventSecurityException {
105         return mUiController.injectString(str);
106     }
107 
108     @Override
loopMainThreadForAtLeast(long millisDelay)109     public void loopMainThreadForAtLeast(long millisDelay) {
110         mUiController.loopMainThreadForAtLeast(millisDelay);
111     }
112 
113     @Override
loopMainThreadUntilIdle()114     public void loopMainThreadUntilIdle() {
115         mUiController.loopMainThreadUntilIdle();
116     }
117 }
118