1 /*
2  * Copyright (C) 2018 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;
18 
19 import static android.view.Display.INVALID_DISPLAY;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 
24 import android.os.Parcel;
25 
26 import androidx.test.ext.junit.runners.AndroidJUnit4;
27 import androidx.test.filters.SmallTest;
28 
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 
32 import java.util.HashSet;
33 import java.util.Set;
34 
35 @SmallTest
36 @RunWith(AndroidJUnit4.class)
37 public class KeyEventTest {
38 
39     private static final int ID = 0xabcdef;
40     private static final int DOWN_TIME = 50;
41     private static final long EVENT_TIME = 100;
42     private static final int ACTION = KeyEvent.ACTION_DOWN;
43     private static final int KEYCODE = KeyEvent.KEYCODE_0;
44     private static final int REPEAT = 0;
45     private static final int METASTATE = 0;
46     private static final int DEVICE_ID = 0;
47     private static final int SCAN_CODE = 0;
48     private static final int FLAGS = 0;
49     private static final int SOURCE = InputDevice.SOURCE_KEYBOARD;
50     private static final byte[] HMAC = null;
51     private static final String CHARACTERS = null;
52 
53     private static final int ID_SOURCE_MASK = 0x3 << 30;
54 
55     @Test
testObtain()56     public void testObtain() {
57         KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
58                 METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
59         assertEquals(DOWN_TIME, keyEvent.getDownTime());
60         assertEquals(EVENT_TIME, keyEvent.getEventTime());
61         assertEquals(ACTION, keyEvent.getAction());
62         assertEquals(KEYCODE, keyEvent.getKeyCode());
63         assertEquals(REPEAT, keyEvent.getRepeatCount());
64         assertEquals(METASTATE, keyEvent.getMetaState());
65         assertEquals(DEVICE_ID, keyEvent.getDeviceId());
66         assertEquals(SCAN_CODE, keyEvent.getScanCode());
67         assertEquals(FLAGS, keyEvent.getFlags());
68         assertEquals(SOURCE, keyEvent.getSource());
69         assertEquals(INVALID_DISPLAY, keyEvent.getDisplayId());
70         assertEquals(CHARACTERS, keyEvent.getCharacters());
71     }
72 
73     @Test
testObtainFromKeyEvent()74     public void testObtainFromKeyEvent() {
75         KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
76                 METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
77         KeyEvent keyEvent2 = KeyEvent.obtain(keyEvent);
78         compareKeys(keyEvent, keyEvent2);
79     }
80 
81     @Test
testObtainWithDisplayId()82     public void testObtainWithDisplayId() {
83         final int displayId = 5;
84         KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
85                 METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, CHARACTERS);
86         assertEquals(DOWN_TIME, keyEvent.getDownTime());
87         assertEquals(EVENT_TIME, keyEvent.getEventTime());
88         assertEquals(ACTION, keyEvent.getAction());
89         assertEquals(KEYCODE, keyEvent.getKeyCode());
90         assertEquals(REPEAT, keyEvent.getRepeatCount());
91         assertEquals(METASTATE, keyEvent.getMetaState());
92         assertEquals(DEVICE_ID, keyEvent.getDeviceId());
93         assertEquals(SCAN_CODE, keyEvent.getScanCode());
94         assertEquals(FLAGS, keyEvent.getFlags());
95         assertEquals(SOURCE, keyEvent.getSource());
96         assertEquals(displayId, keyEvent.getDisplayId());
97         assertEquals(CHARACTERS, keyEvent.getCharacters());
98     }
99 
100     /**
101      * Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test
102      * but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough.
103      * Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for
104      * this test.
105      */
106     @Test
testObtainGeneratesUniqueId()107     public void testObtainGeneratesUniqueId() {
108         Set<Integer> set = new HashSet<>();
109         for (int i = 0; i < 500; ++i) {
110             KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
111                     METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
112             assertFalse("Found duplicate ID in round " + i,
113                     set.contains(keyEvent.getId()));
114             set.add(keyEvent.getSequenceNumber());
115         }
116     }
117 
118     @Test
testConstructorGeneratesUniqueId()119     public void testConstructorGeneratesUniqueId() {
120         Set<Integer> set = new HashSet<>();
121         for (int i = 0; i < 500; ++i) {
122             KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
123             assertFalse("Found duplicate sequence number in round " + i,
124                     set.contains(keyEvent.getId()));
125             set.add(keyEvent.getSequenceNumber());
126         }
127     }
128 
129     @Test
testObtainGeneratesIdWithRightSource()130     public void testObtainGeneratesIdWithRightSource() {
131         for (int i = 0; i < 500; ++i) {
132             KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
133                     METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
134             assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
135         }
136     }
137 
138     @Test
testConstructorGeneratesIdWithRightSource()139     public void testConstructorGeneratesIdWithRightSource() {
140         for (int i = 0; i < 500; ++i) {
141             KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
142             assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
143         }
144     }
145 
146     @Test
testParcelUnparcel()147     public void testParcelUnparcel() {
148         KeyEvent key1 = createKey();
149         Parcel parcel = Parcel.obtain();
150         key1.writeToParcel(parcel, 0 /*flags*/);
151         parcel.setDataPosition(0);
152 
153         KeyEvent key2 = KeyEvent.CREATOR.createFromParcel(parcel);
154         parcel.recycle();
155 
156         compareKeys(key1, key2);
157     }
158 
159     @Test
testConstructor()160     public void testConstructor() {
161         KeyEvent key1 = createKey();
162         KeyEvent key2 = new KeyEvent(key1);
163         compareKeys(key1, key2);
164     }
165 
createKey()166     private static KeyEvent createKey() {
167         return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
168                 DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS);
169     }
170 
compareKeys(KeyEvent key1, KeyEvent key2)171     private static void compareKeys(KeyEvent key1, KeyEvent key2) {
172         assertEquals(key1.getId(), key2.getId());
173         assertEquals(key1.getDownTime(), key2.getDownTime());
174         assertEquals(key1.getEventTime(), key2.getEventTime());
175         assertEquals(key1.getAction(), key2.getAction());
176         assertEquals(key1.getKeyCode(), key2.getKeyCode());
177         assertEquals(key1.getRepeatCount(), key2.getRepeatCount());
178         assertEquals(key1.getMetaState(), key2.getMetaState());
179         assertEquals(key1.getDeviceId(), key2.getDeviceId());
180         assertEquals(key1.getScanCode(), key2.getScanCode());
181         assertEquals(key1.getFlags(), key2.getFlags());
182         assertEquals(key1.getSource(), key2.getSource());
183         assertEquals(key1.getDisplayId(), key2.getDisplayId());
184         assertEquals(key1.getCharacters(), key2.getCharacters());
185     }
186 }
187