1 /*
2  * Copyright (C) 2019 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.accessibilityservice.cts.utils;
18 
19 import static android.view.MotionEvent.ACTION_HOVER_MOVE;
20 import static java.util.concurrent.TimeUnit.SECONDS;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 
26 import android.view.MotionEvent;
27 import android.view.View;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.BlockingQueue;
31 import java.util.concurrent.LinkedBlockingQueue;
32 
33 /** This Listener listens for and logs hover events so they can be checked later by tests. */
34 public class EventCapturingHoverListener implements View.OnHoverListener {
35 
36     private boolean shouldConsumeEvents; // whether or not to keep events from propagating to other
37     // listeners
38     private final BlockingQueue<MotionEvent> mEvents = new LinkedBlockingQueue<>();
39 
EventCapturingHoverListener(boolean shouldConsumeEvents)40     public EventCapturingHoverListener(boolean shouldConsumeEvents) {
41         this.shouldConsumeEvents = shouldConsumeEvents;
42     }
43 
EventCapturingHoverListener()44     public EventCapturingHoverListener() {
45         this.shouldConsumeEvents = true;
46     }
47 
48     @Override
onHover(View view, MotionEvent MotionEvent)49     public boolean onHover(View view, MotionEvent MotionEvent) {
50         assertTrue(mEvents.offer(MotionEvent.obtain(MotionEvent)));
51         return shouldConsumeEvents;
52     }
53 
54     /** Insure that no hover events have been detected. */
assertNonePropagated()55     public void assertNonePropagated() {
56         try {
57             long waitTime = 1; // seconds
58             MotionEvent event = mEvents.poll(waitTime, SECONDS);
59             if (event != null) {
60                 fail("Unexpected touch event " + event.toString());
61             }
62         } catch (InterruptedException e) {
63             throw new RuntimeException(e);
64         }
65     }
66 
67     /**
68      * Check for the specified hover events. Note that specifying ACTION_HOVER_MOVE will match one
69      * or more consecutive ACTION_HOVER_MOVE events.
70      */
assertPropagated(int... eventTypes)71     public void assertPropagated(int... eventTypes) {
72         MotionEvent ev;
73         long waitTime = 5; // seconds
74         try {
75             List<String> expected = new ArrayList<>();
76             List<String> received = new ArrayList<>();
77             for (int e : eventTypes) {
78                 expected.add(MotionEvent.actionToString(e));
79             }
80             ev = mEvents.poll(waitTime, SECONDS);
81             assertNotNull(
82                     "Expected " + expected + " but none present after " + waitTime + " seconds",
83                     ev);
84             // By this point there is at least one received event.
85             received.add(MotionEvent.actionToString(ev.getActionMasked()));
86             ev = mEvents.poll(waitTime, SECONDS);
87             while (ev != null) {
88                 int action = ev.getActionMasked();
89                 if (action != ACTION_HOVER_MOVE) {
90                     received.add(MotionEvent.actionToString(action));
91                 } else {
92                     // Add the current event if the previous received event was not ACTION_MOVE
93                     String prev = received.get(received.size() - 1);
94                     if (!prev.equals(MotionEvent.actionToString(ACTION_HOVER_MOVE))) {
95                         received.add(MotionEvent.actionToString(action));
96                     }
97                 }
98                 ev = mEvents.poll(waitTime, SECONDS);
99             }
100             assertEquals(expected, received);
101         } catch (InterruptedException e) {
102             throw new RuntimeException(e);
103         }
104     }
105 }
106