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